springSecurity自定义认证逻辑

       在 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中完整代码。

 

启动项目,登录后,关闭项目和浏览器,再启动项目和打开浏览器,就访问项目中接口,发现不用登录也可以访问了,也就是实现了记住我的功能。

你可能感兴趣的:(springSecurity)