在 springSecurity入门demo 中,用户信息是放在内存中的,而在真实的项目中,肯定是不会是这样的,一般是都是放在数据库中存储的。示例代码在GitHub中:https://github.com/qiuxinfa/springSecurity-study 。实现如下功能:
(1)自定义用户信息的获取
(2)自定义认证成功以及失败后的回调
(3)实现记住我的功能
1. 创建maven工程,添加如下依赖:
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-security
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.0.1
mysql
mysql-connector-java
8.0.11
因为要用到数据库,这里使用的是mysql。
2.实现UserDetailsService接口,重写loadUserByUsername(),获取用户信息:
@Service
public class UserService implements UserDetailsService{
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return userMapper.getUserByUsername(username);
}
}
3.实现AuthenticationSuccessHandler接口,认证成功后回调:
@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler{
//spring会自动注册一个ObjectMapper
@Autowired
private ObjectMapper objectMapper;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
System.out.println("登录成功:"+authentication.getName());
//设置返回的格式及其编码
response.setContentType("application/json;charset=UTF-8");
//将已认证信息转换为json格式写到页面
response.getWriter().write("登录成功:"+objectMapper.writeValueAsString(authentication));
}
}
4.实现 AuthenticationFailureHandler 接口,认证失败后回调:
@Component
public class MyAuthenticationFailuerHandler implements AuthenticationFailureHandler{
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
System.out.println("登录失败:"+e.getMessage());
//设置返回的格式及其编码
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("登录失败:"+e.getMessage());
}
}
5.继承WebSecurityConfigurerAdapter,自定义配置,详细解释都在代码中了:
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
private AuthenticationSuccessHandler myAuthenticationSuccessHandler;
@Autowired
private AuthenticationFailureHandler myAuthenticationFailureHandler;
@Autowired
private UserDetailsService userService;
@Autowired
private DataSource dataSource;
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public PersistentTokenRepository persistentTokenRepository(){
JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
tokenRepository.setDataSource(dataSource);
//第一次就打开,然它创建表,一次就够了
// tokenRepository.setCreateTableOnStartup(true);
return tokenRepository;
}
@Override
public void configure(WebSecurity web) throws Exception {
//放行静态资源
web.ignoring().antMatchers("/js/**", "/css/**","/images/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() //允许基于使用HttpServletRequest限制访问
//所有请求都需要认证
.anyRequest().authenticated()
.and()
//表单登录
.formLogin()
//登录页面和处理接口
.loginPage("/login.html")
//认证成功后的处理器
.successHandler(myAuthenticationSuccessHandler)
//认证失败后的处理器
.failureHandler(myAuthenticationFailureHandler)
.permitAll()
.and()
.rememberMe()
.tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(60*60*24*7)
.userDetailsService(userService)
.and()
//关闭跨站请求伪造的防护,这里是为了前期开发方便
.csrf().disable();
}
}
简单说一下记住我功能实现的相关配置:
(1)首先,需要一个PersistentTokenRepository,将cookie信息保存到数据库中,包括了用户名,随机生成的序列号,token等信息,以后就可以通过cookie,查询数据库,得到用户名,再通过用户名,查询用户信息了。
@Bean
public PersistentTokenRepository persistentTokenRepository(){
JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
tokenRepository.setDataSource(dataSource);
//第一次就打开,然它创建表,一次就够了
// tokenRepository.setCreateTableOnStartup(true);
return tokenRepository;
}
(2)然后在configure(HttpSecurity http)方法中配置记住我:
.rememberMe()
.tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(60*60*24*7)
.userDetailsService(userService)
这里的tokenRepository就是(1)配置的PersistentTokenRepository
实体类,mapper等其他可以查看GitHub中完整代码。
启动项目,登录后,关闭项目和浏览器,再启动项目和打开浏览器,就访问项目中接口,发现不用登录也可以访问了,也就是实现了记住我的功能。