搜档网
当前位置:搜档网 › Spring boot 和Spring Security4最新整合实例

Spring boot 和Spring Security4最新整合实例

Spring boot 和Spring Security4最新整合实例
Spring boot 和Spring Security4最新整合实例

Spring boot+Spring Security 4配置整合实例

本例所覆盖的内容:

1.使用Spring Security管理用户身份认证、登录退出

2.用户密码加密及验证

3.采用数据库的方式实现Spring Security的remember-me功能

4.获取登录用户信息。

本例所使用的框架:

1.Spring boot

2.Spring MVC

3.Spring Security

4.Spring Data JPA

5.thymeleaf

说明:

1.本文针对采用Spring boot微框架之用户,完全采用Java config,不讨论xml配置。

2.本例代码是完整的,请勿随意删减,否则不能运行。

一、整合Spring Security

在pom.xml中加入如下片段:

org.springframework.security

spring-security-web

org.springframework.security

spring-security-config

二、配置Spring Security

几乎所有配置都在下面这个文件中完成:

@Configuration

@EnableWebMvcSecurity

public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired

private CustomUserDetailsService customUserDetailsService;//code1

@Autowired@Qualifier("dataSource1")

private DataSource dataSource1; //code2

@Override

protected void configure(HttpSecurity http) throws Exception { //允许所有用户访问”/”和”/home”

http.authorizeRequests().antMatchers("/", "/home").permitAll() //其他地址的访问均需验证权限

.anyRequest().authenticated()

.and()

.formLogin()

//指定登录页是”/login”

.loginPage("/login")

.permitAll()

//登录成功后可使用loginSuccessHandler()存储用户信息,可选。

.successHandler(loginSuccessHandler())//code3

.and()

.logout()

//退出登录后的默认网址是”/home”

.logoutSuccessUrl("/home")

.permitAll()

.invalidateHttpSession(true)

.and()

//登录后记住用户,下次自动登录

//数据库中必须存在名为persistent_logins的表

//建表语句见code15

.rememberMe()

.tokenValiditySeconds(1209600)

//指定记住登录信息所使用的数据源

.tokenRepository(tokenRepository());//code4

}

@Autowired

public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

//指定密码加密所使用的加密器为passwordEncoder()

//需要将密码加密后写入数据库//code13

https://www.sodocs.net/doc/185996146.html,erDetailsService(customUserDetailsService).passwordEncoder (passwordEncoder());//code5

//不删除凭据,以便记住用户

auth.eraseCredentials(false);

}

// Code5----------------------------------------------

@Bean

public BCryptPasswordEncoder passwordEncoder() {

return new BCryptPasswordEncoder(4);

}

// Code4----------------------------------------------

@Bean

public JdbcTokenRepositoryImpl tokenRepository(){

JdbcTokenRepositoryImpl j=new JdbcTokenRepositoryImpl();

j.setDataSource(dataSource1);

return j;

}

// Code3----------------------------------------------

@Bean

public LoginSuccessHandler loginSuccessHandler(){

return new LoginSuccessHandler();//code6

}

}

code1----------------------------------------------

@Component

public class CustomUserDetailsService implements UserDetailsService { @Autowired //数据库服务类

private SUserService suserService;//code7

@Override

public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {

//SUser对应数据库中的用户表,是最终存储用户和密码的表,可自定义

//本例使用SUser中的email作为用户名:

SUser user = suserService.findUserByEmail(userName); //code8

if (user == null) {

throw new UsernameNotFoundException("UserName "+ userName+

" not found");

}

//SecurityUser实现UserDetails并将SUser的Email映射为username

return new SecurityUser(user); //code9

}

}

Code2----------------------------------------------

@Configuration

@EnableAutoConfiguration(exclude =

{ DataSourceAutoConfiguration.class })

public class MyConfiguration {

@Bean

public DataSource dataSource1() {

org.springframework.jdbc.datasource.DriverManagerDataSource ds = new org.springframework.jdbc.datasource.DriverManagerDataSource();

ds.setDriverClassName("com.mysql.jdbc.Driver");

ds.setUrl("jdbc:mysql://localhost:3306/test");

ds.setUsername("root");

ds.setPassword("****");

return ds;

}

}

Code6----------------------------------------------

//可以在这里将用户登录信息存入数据库。

public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler{

@Override

public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException,

ServletException {

//获得授权后可得到用户信息可使用SUserService进行数据库操作

SUser userDetails = (SUser)authentication.getPrincipal();

//输出登录提示信息

System.out.println("管理员 " + userDetails.getEmail() + " 登录"); System.out.println("IP :"+getIpAddress(request));

super.onAuthenticationSuccess(request, response,

authentication);

}

public String getIpAddress(HttpServletRequest request){

String ip = request.getHeader("x-forwarded-for");

if (ip == null || ip.length() == 0 ||

"unknown".equalsIgnoreCase(ip)) {

ip = request.getHeader("Proxy-Client-IP");

}

if (ip == null || ip.length() == 0 ||

"unknown".equalsIgnoreCase(ip)) {

ip = request.getHeader("WL-Proxy-Client-IP");

}

if (ip == null || ip.length() == 0 ||

"unknown".equalsIgnoreCase(ip)) {

ip = request.getHeader("HTTP_CLIENT_IP");

}

if (ip == null || ip.length() == 0 ||

"unknown".equalsIgnoreCase(ip)) {

ip = request.getHeader("HTTP_X_FORWARDED_FOR");

}

if (ip == null || ip.length() == 0 ||

"unknown".equalsIgnoreCase(ip)) {

ip = request.getRemoteAddr();

}

return ip;

}

}

Code7----------------------------------------------

@Service("suserService")

public class SUserService {

@Autowired

private SUserRepository suserRepository;//code10

public List findAll() {

return suserRepository.findAll();

}

public SUser create(SUser user) {

return suserRepository.save(user);

}

public SUser findUserById(int id) {

return suserRepository.findOne(id);

}

public SUser login(String email, String password) {

return suserRepository.findByEmailAndPassword(email, password);

}

public SUser update(SUser user) {

return suserRepository.save(user);

}

public void deleteUser(int id) {

suserRepository.delete(id);

}

public SUser findUserByEmail(String email) {

return suserRepository.findUserByEmail(email);

}

}

Code8----------------------------------------------

@Entity

@Table(name = "s_user", catalog = "test")//code11

public class SUser implements java.io.Serializable {

private Integer id;

private String name;

private String email;

private String password;

private Date dob;

private Set SRoles = new HashSet(0);// Code12

public SUser() {

}

public SUser(String name, String email, String password, Date dob, Set SRoles) {

https://www.sodocs.net/doc/185996146.html, = name;

this.email = email;

this.password = password;

this.dob = dob;

this.SRoles = SRoles;

}

@Id

@GeneratedValue(strategy = IDENTITY)

@Column(name = "id", unique = true, nullable = false)

public Integer getId() {

return this.id;

}

public void setId(Integer id) {

this.id = id;

}

@Column(name = "name", length = 20)

public String getName() {

return https://www.sodocs.net/doc/185996146.html,;

}

public void setName(String name) {

https://www.sodocs.net/doc/185996146.html, = name;

}

@Column(name = "email", length = 20)

public String getEmail() {

return this.email;

}

public void setEmail(String email) {

this.email = email;

}

@Column(name = "password", length = 20)

public String getPassword() {

return this.password;

}

public void setPassword(String password) {

this.password = password;

}

@Temporal(TemporalType.DATE)

@Column(name = "dob", length = 10)

public Date getDob() {

return this.dob;

}

public void setDob(Date dob) {

this.dob = dob;

}

@OneToMany(fetch = FetchType.EAGER, mappedBy = "SUser")

public Set getSRoles() {

return this.SRoles;

}

public void setSRoles(Set SRoles) {

this.SRoles = SRoles;

}

}

Code9----------------------------------------------

public class SecurityUser extends SUser implements UserDetails {

private static final long serialVersionUID = 1L;

public SecurityUser(SUser suser) {

if(suser != null)

{

this.setId(suser.getId());

this.setName(suser.getName());

this.setEmail(suser.getEmail());

this.setPassword(suser.getPassword());

this.setDob(suser.getDob());

this.setSRoles(suser.getSRoles());

}

}

@Override

public Collection getAuthorities() {

Collection authorities = new ArrayList<>();

Set userRoles = this.getSRoles();

if(userRoles != null)

{

for (SRole role : userRoles) {

SimpleGrantedAuthority authority = new SimpleGrantedAuthority(role.getName());

authorities.add(authority);

}

}

return authorities;

}

@Override

public String getPassword() {

return super.getPassword();

}

@Override

public String getUsername() {

return super.getEmail();

}

@Override

public boolean isAccountNonExpired() {

return true;

}

@Override

public boolean isAccountNonLocked() {

return true;

}

@Override

public boolean isCredentialsNonExpired() {

return true;

}

@Override

public boolean isEnabled() {

return true;

}

}

Code10----------------------------------------------

public interface SUserRepository extends JpaRepository {

@Query("select u from SUser u where u.email=?1 and u.password=?2") SUser login(String email, String password);

SUser findByEmailAndPassword(String email, String password);

SUser findUserByEmail(String email);

}

Code11----------------------------------------------

SUser对应的表和角色表,一个都不能少

CREATE TABLE `s_user` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`name` varchar(20) DEFAULT NULL,

`email` varchar(20) DEFAULT NULL,

`password` varchar(60) DEFAULT NULL,

`dob` date DEFAULT NULL,

PRIMARY KEY (`id`)

)

CREATE TABLE `s_role` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`name` varchar(20) DEFAULT NULL,

`uid` int(11) NOT NULL,

PRIMARY KEY (`id`),

KEY `userrole` (`uid`),

CONSTRAINT `userrole` FOREIGN KEY (`uid`) REFERENCES `s_user` (`id`) )

Code12----------------------------------------------

@Entity

@Table(name = "s_role", catalog = "test")

public class SRole implements java.io.Serializable {

private Integer id;

private SUser SUser;

private String name;

public SRole() {

}

public SRole(SUser SUser) {

this.SUser = SUser;

}

public SRole(SUser SUser, String name) {

this.SUser = SUser;

https://www.sodocs.net/doc/185996146.html, = name;

}

@Id

@GeneratedValue(strategy = IDENTITY)

@Column(name = "id", unique = true, nullable = false) public Integer getId() {

return this.id;

}

public void setId(Integer id) {

this.id = id;

}

@ManyToOne(fetch = https://www.sodocs.net/doc/185996146.html,ZY)

@JoinColumn(name = "uid", nullable = false)

public SUser getSUser() {

return this.SUser;

}

public void setSUser(SUser SUser) {

this.SUser = SUser;

}

@Column(name = "name", length = 20)

public String getName() {

return https://www.sodocs.net/doc/185996146.html,;

}

public void setName(String name) {

https://www.sodocs.net/doc/185996146.html, = name;

}

}

Code13----------------------------------------------

@SpringBootApplication

public class Application {

@SuppressWarnings("unchecked")

public static void main(String[] args) {

SpringApplication app=new SpringApplication(Application.class);

Appctx.ctx=app.run(args);//将密码加密必须保证数据库s_user中有id为1的用户//code14

SUserService suserService = (SUserService)

Appctx.ctx.getBean("suserService");

SUser su= suserService.findUserById(1);

BCryptPasswordEncoder bc=new BCryptPasswordEncoder(4);

su.setPassword(bc.encode("111111"));

suserService.update(su);

}

Code14----------------------------------------------

public class Appctx {

public static ApplicationContext ctx=null;

public static Object getObject(String string){

r eturn ctx.getBean(string);

}

}

Code15----------------------------------------------

//请勿手工写入数据供remember-me功能使用

CREATE TABLE `persistent_logins` (

`username` varchar(64) NOT NULL,

`series` varchar(64) NOT NULL,

`token` varchar(64) NOT NULL,

`last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

PRIMARY KEY (`series`)

)

Code15----------------------------------------------

public interface SRoleRepository extends JpaRepository { }

三、H tml及controller

index.html:

Insert title here

Welcome to Spring technology page!

hello.html

xmlns:th="https://www.sodocs.net/doc/185996146.html,"

xmlns:sec="https://www.sodocs.net/doc/185996146.html,/thymeleaf-extras-springsecurity3" >

Hello World!

Hello

[[${#httpServletRequest.remoteUser}]]!

home.html

xmlns:th="https://www.sodocs.net/doc/185996146.html,"

xmlns:sec="https://www.sodocs.net/doc/185996146.html,/thymeleaf-extras-springsecurity3" >

Spring Security Example

Welcome!

Click here to see a greeting.

login.html

本页中 username password remember-me三个控件请勿改名。

xmlns:th="https://www.sodocs.net/doc/185996146.html,"

xmlns:sec="https://www.sodocs.net/doc/185996146.html,/thymeleaf-extras-springsecurity3" >

Spring Security Example

Invalid username and password.

You have been logged out.

sample_user

th:checked="checked"/>

Remember me

Controller:

@Controller

@RequestMapping("/")

public class GreetingController {

@RequestMapping("/home")

public String home() {

return"home";

}

@RequestMapping("/hello")

public String hello() {

SecurityContext ctx = SecurityContextHolder.getContext(); Authentication auth = ctx.getAuthentication();

if(auth.getPrincipal() instanceof UserDetails)

{

SUser user = (SUser)auth.getPrincipal();

System.out.println(user.getEmail());

}

//本段代码演示如何获取登录的用户资料

return"hello";

}

@RequestMapping("/")

public String root() {

//如不进行此项配置,从login登录成功后,会提示找不网页

return"index";

}

}

四、构建及运行顺序

1.首先建立s_user s_role表,并向表中写入数据

2.建立SUserService SUserRepository SUser SRoleRepository SRole类

3.运行程序,将s_user中用户的密码加密

4.如三中所述,配置Spring Security

5.运行,访问http://localhost:8080/hello,系统出现如下界面:

用户名输入useremail 密码输入111111,点sign in则进入hello.html

重启浏览器,再访问http://localhost:8080/hello,则无需登录,直接到达。

在hello页面点sign out后,则返回home页面,退出了登录。

相关主题