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