SpringBoot学习-自定义UsernamePasswordAuthenticationFilter-(Security自定义登录验证规则)


  众所周知SpringBoot-Security可以继承WebSecurityConfigurerAdapter来进行登录验证,若我们想自定义登录验证的规则,则可以编写一个登录过滤的类通过继承UsernamePasswordAuthenticationFilter,关于这方面的内容,我是通过看松哥的微人事项目进行的简单学习,这里贴上松哥的博客地址:http://springboot.javaboy.org/2019/1120/springboot-vue,感谢松哥的贡献。

  我来简单的写一下个人对这个的理解,若有错误之处,希望大家能在评论区指出。

 1 /**
 2  * 该类主要是自定义登录验证的规则,包括检查验证码
 3  */
 4 public class LoginFilter extends UsernamePasswordAuthenticationFilter {
 5     @Autowired
 6     private SessionRegistry sessionRegistry; //用于向session里注册用户
 7 
 8     @Override
 9     public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
10         //登录表单只支持post,进行验证
11         if(!request.getMethod().equals("POST")){
12             throw new AuthenticationServiceException(
13                     "Authentication method not supported: " + request.getMethod());
14         }
15         //如果请求类型为json的话,自定义处理
16         String localCode = (String) request.getSession().getAttribute("verify_code");
17         String verifyCode = null;
18         if(request.getContentType().contains(MediaType.APPLICATION_JSON_VALUE) || request.getContentType().contains(MediaType.APPLICATION_JSON_UTF8_VALUE)){
19             Map<String,String> loginData = new HashMap<>();//用于存放登录用户信息的键值对
20             try {
21                 //把请求里信息读进map
22                loginData =  new ObjectMapper().readValue(request.getInputStream(), Map.class);
23             } catch (IOException e) {
24                 e.printStackTrace();
25             }finally {
26                 verifyCode = loginData.get("code");
27                 checkCode(localCode,verifyCode);
28                 //以后要在这里进行检查验证码
29             }
30             //通过父类提供的方法获取用户名密码
31             String username = loginData.get(getUsernameParameter());
32             String password = loginData.get(getPasswordParameter());
33             //这一步照抄父类的处理,可能是处理为空时候的用户密码?
34             if(username==null){
35                 username="";
36             }
37             if(password==null){
38                 password="";
39             }
40             username=username.trim(); //去除用户名前后的空格
41             //开始验证
42             UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
43             setDetails(request,authRequest);
44             //向session里注册此用户
45             Hr principal = new Hr();
46             principal.setName(username);
47             sessionRegistry.registerNewSession(request.getSession(true).getId(),principal);
48             return this.getAuthenticationManager().authenticate(authRequest); //获取身份验证管理器,提交令牌验证
49         } else {
50             //检查一下验证码,然后直接调用父类的
51             checkCode(localCode,verifyCode);
52             return super.attemptAuthentication(request,response);
53         }
54     }
55 
56     private void checkCode(String localCode,String verifyCode){
57         if(verifyCode==null || verifyCode.equals("") || localCode==null || localCode.equals("") || !localCode.toLowerCase().equals(verifyCode.toLowerCase())){
58             throw new AuthenticationServiceException("验证码不正确!");
59         }
60     }
61 }

  在这篇代码中,主要是希望登录数据以JSON的方式传送过来,所以在开头进行了request类型是否为JSON的验证,又通过JACKSON提供的ObjectMapper().readValue将request请求的数据读成Map形式存储。中间的处理过程完全参照父类UsernamePasswordAuthenticationFilter里的处理,最后向session注册一个用户。

  综上举一反三,若想进行其他的一些数据处理或者判断,都可以以继承这个类的方式自定义,比如里面的验证码的验证。父类还提供了一些其他非常有用的方法,比如getUsernameParameter,可以直接获取到传过来的username,当然你也可以自定义。

  最后在SecurityConfig里new 一个LoginFilter的实例,在重写的configure(HttpSecurity http)方法里,以AOP形式织入。

http.addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class);

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM