天天看點

SpringSecurity整合短信驗證碼認證

SMS認證

1. Sms認證原理

SpringSecurity整合短信驗證碼認證

1.使用者前端發起請求,擷取短信驗證碼。後端通過SmsController傳回結果,并将驗證碼儲存在session中(如果是無狀态就儲存在緩存中,設定過期時間)。

2.使用者用手機号和驗證碼發起登入請求,通過SmsVaildataFilter過濾器進行校驗,如果失敗傳回失敗結果,校驗成功後繼續往下一個過濾器走。

3.通過SmsAuthencationFilter調用UserService進行認證。

2. SmsAuthencationFilter

2.1 Sms使用者認證概述

SpringSecurity整合短信驗證碼認證

在短信驗證登入的過程中,前邊的各種校驗相對簡單,而SmsAuthencationFilter中的各種方法需要了解。

首先在SpringSecurity中認證和鑒權是兩種操作。根據使用者手機号擷取驗證碼校驗驗證碼,僅僅隻是對驗證碼的操作,并沒有實作使用者的認證。校驗完了驗證碼沒有認證對于伺服器内部的接口還是不能夠進行通路,并沒有什麼卵用,說白了就是前邊的前邊的操作隻是看了看使用者的驗證碼和手機号比對麼,SmsAuthencationFilter中的操作就是實作使用者的認證。

何為使用者的認證?我了解的使用者認證就是通過一系列的操作,将使用者的資訊儲存在Authentication對象中,通過authenticated值(true,false)來判斷使用者是否被認證。(劃重點,在SpringSecurity架構中見到的Authentication對象中儲存的都是對象的主體)。

2.2 Sms使用者認證的過程

微觀上看這個過程就是對SmsCodeAuthenticationToken的一系列操作,先是将使用者手機号儲存在Token中,然後通過認證将使用者的資料儲存在Token中,其中authenticated值為true時就是校驗通過。

SpringSecurity整合短信驗證碼認證
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
       //判斷請求是否是post請求
        if (this.postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        } else {
          //擷取請求中的參數,obtainMobile是定義的方法擷取參數。
            String mobile = this.obtainMobile(request);
            if (mobile == null) {
                mobile = "";
            }
            mobile = mobile.trim();
          //生成Token,此時Token中隻有手機号
            SmsCodeAuthenticationToken authRequest = new SmsCodeAuthenticationToken(mobile);
          //通過此方法将資料封裝到Authentication中
            this.setDetails(request, authRequest);
          //調用authenticate方法校驗,(SmsCodeAuthenticationProvider中的方法)
            return this.getAuthenticationManager().authenticate(authRequest);
        }
    }
           

1.通過層層過濾器,我們的手機号來到了最關鍵的過濾器中,SmsAuthenticationFilter,首先通過SmsCodeAuthenticationToken生成一個Token對象,将手機号儲存在裡邊。

2.調用SmsCodeAuthenticationProvider中的authenticate方法進行驗證,authenticate方法調用的UserDetailService中的loadByUsername方法傳回UserDetails類型的對象。再次成SmsCodeAuthenticationToken對象,将使用者資料儲存在Token中,包裝成Authention傳回給SmsAuthenticationFilter

3.Security上下文排程,執行下一個過濾操作。

//擷取儲存在Authentication中的使用者資料(在SmsAuthenticationFilter中通過attemptAuthentication方法調用,隻儲存了手機号)
        SmsCodeAuthenticationToken authenticationToken=(SmsCodeAuthenticationToken) authentication;
        //通過手機号進行查詢使用者的資訊
        UserDetails userDetails=userDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal());
        if (userDetails==null){
            throw new InternalAuthenticationServiceException("無法根據手機号擷取使用者資訊");
        }
        //再次成SmsCodeAuthenticationToken對象,這次裡邊存儲的是使用者資訊。這個構造方法會調用setAuthenticate(true)表示認證通過了
        SmsCodeAuthenticationToken authenticationResult=new SmsCodeAuthenticationToken(userDetails,userDetails.getAuthorities());
        authenticationResult.setDetails(authenticationToken.getDetails());
        return authenticationResult;
           

3. SmsCodeSecurityConfig

經過了一系列的操作,什麼過濾器,各種校驗。。。。都搭建好了。

考慮一個問題:目前端發起短信登入請求時,憑什麼就得用SmsAuthenticaionFilter,這個過濾器來處理認證請求呢?為什麼不用UsernamePasswordFilter處理? (黑人???.jpg)

認證過濾器是需要配置的,需要我們手動的告訴SpringSecurity,不廢話直接上代碼。

SmsAuthenticationFilter smsAuthenticationFilter=new SmsAuthenticationFilter();
//認證管理器通過認證必選要有,作用是通過周遊選擇合适的Provider
smsAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
//配置認證成功的處理操作
smsAuthenticationFilter.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler);
//配置認證失敗的處理操作        
smsAuthenticationFilter.setAuthenticationFailureHandler(myAuthenticationFailureHandler);
//配置Provider重點是邊的authenticate方法
SmsCodeAuthenticationProvider smsCodeAuthenticationProvider=new SmsCodeAuthenticationProvider();
//給Provider配置自己的UserDetailService    
smsCodeAuthenticationProvider.setUserDetailsService(myUserDetailsService);
//将驗證碼校驗的過濾器配置到UsernamePasswordAuthenticationFilter前邊
http.addFilterBefore(smsCodeValidateFilter, UsernamePasswordAuthenticationFilter.class);
//配置Provider重點是邊的authenticate方法
http.authenticationProvider(smsCodeAuthenticationProvider)
//将使用者認證的過濾器配置到UsernamePasswordAuthenticationFilter後邊              .addFilterAfter(smsAuthenticationFilter,UsernamePasswordAuthenticationFilter.class);
           

重點說一下,過濾器鍊的配置,使用者發起"/smslogin"請求先進行驗證碼的校驗,然後走UsernamePasswordAuthenticationFilter請求發現不是"/login"請求,走下一個過濾器,來到了SmsAuthenticationFilter進行校驗。然後認證成功,傳回資料,在進行access鑒權。

最後需要在WebSecurityConfigurerAdapter中裝配上smsCodeSecurityConfig

以上内容依據本人了解所寫,如有偏差歡迎指正,互相學習,沒有實作發送短信的第三方接口。在控制台列印。

源碼位置:SpringSecurity

繼續閱讀