Spring Security 實戰干貨: 登錄成功后返回 JWT Token


jwtlogin.png

1. 前言

歡迎閱讀 Spring Security 實戰干貨 系列文章上一文 我們實現了 JWT 工具。本篇我們將一起探討如何將 JWTSpring Security 結合起來,在認證成功后不再跳轉到指定頁面而是直接返回 JWT Token 。 本文的**DEMO 可通過文末的方式獲取**

2. 流程

JWT 適用於前后端分離。我們在登錄成功后不在跳轉到首頁,將會直接返回 JWT Token 對(DEMO中為JwtTokenPair),登錄失敗后返回認證失敗相關的信息。

3. 實現登錄成功/失敗返回邏輯

如果你看過 Spring Security 實戰干貨: 玩轉自定義登錄 將非常容易理解下面的做法。

3.1 AuthenticationSuccessHandler 返回 JWT Token

AuthenticationSuccessHandler 用於處理登錄成功后的邏輯,我們編寫實現並注入 Spring IoC 容器:

     /** * 處理登錄成功后返回 JWT Token 對. * * @param jwtTokenGenerator the jwt token generator * @return the authentication success handler */
     @Bean
     public AuthenticationSuccessHandler authenticationSuccessHandler(JwtTokenGenerator jwtTokenGenerator) {
         return (request, response, authentication) -> {
             if (response.isCommitted()) {
                 log.debug("Response has already been committed");
                 return;
             }
             Map<String, Object> map = new HashMap<>(5);
             map.put("time", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
             map.put("flag", "success_login");
             User principal = (User) authentication.getPrincipal();
 
             String username = principal.getUsername();
             Collection<GrantedAuthority> authorities = principal.getAuthorities();
             Set<String> roles = new HashSet<>();
             if (CollectionUtil.isNotEmpty(authorities)) {
                 for (GrantedAuthority authority : authorities) {
                     String roleName = authority.getAuthority();
                     roles.add(roleName);
                 }
             }
 
             JwtTokenPair jwtTokenPair = jwtTokenGenerator.jwtTokenPair(username, roles, null);
 
             map.put("access_token", jwtTokenPair.getAccessToken());
             map.put("refresh_token", jwtTokenPair.getRefreshToken());
 
             ResponseUtil.responseJsonWriter(response, RestBody.okData(map, "登錄成功"));
         };
     }

3.2 AuthenticationFailureHandler 返回認證失敗信息

AuthenticationFailureHandler 處理認證失敗后的邏輯,前端根據此返回進行跳轉處理邏輯,我們也實現它並注入 Spring IoC 容器:

    /** * 失敗登錄處理器 處理登錄失敗后的邏輯 登錄失敗返回信息 以此為依據跳轉 * * @return the authentication failure handler */
    @Bean
    public AuthenticationFailureHandler authenticationFailureHandler() {
        return (request, response, exception) -> {
            if (response.isCommitted()) {
                log.debug("Response has already been committed");
                return;
            }
            Map<String, Object> map = new HashMap<>(2);

            map.put("time", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            map.put("flag", "failure_login");
            ResponseUtil.responseJsonWriter(response, RestBody.build(HttpStatus.UNAUTHORIZED.value(), map, "認證失敗","-9999"));
        };
    } 

4. 配置

把上面寫好的兩個 Handler Bean 寫入 登錄配置,相關片斷如下,詳情參見文末 DEMO:

 httpSecurity.formLogin().loginProcessingUrl(LOGIN_PROCESSING_URL).successHandler(authenticationSuccessHandler).failureHandler(authenticationFailureHandler)

5. 驗證

我們依然通過 Spring Security 實戰干貨: 玩轉自定義登錄 一文中章節 6.4 測試 來運行。結果如下:

5.1 登錄成功結果

 {
     "httpStatus": 200,
     "data": {
         "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhbGwiLCJhdWQiOiJGZWxvcmRjbiIsInJvbGVzIjoiW10iLCJpc3MiOiJmZWxvcmQuY24iLCJleHAiOiIyMDE5LTExLTI3IDExOjMxOjMyIiwiaWF0IjoiMjAxOS0xMC0yOCAxMTozMTozMiIsImp0aSI6IjdmYTBlOWFiYjk5OTRjZGRhNGM5NjI4YzExNGM3YTk4In0.PvVsc8w10_0C5UIifJS1S5dEia5PQoVc_6wMfLAZOf574kt-VopHBVEp2zkjC1CNN3ltchy5rx6samaBDQvqWgoeFLXbRgNOa9Qhdf0wMLf-pUqoKRHuhBZV9HsvXSyQCFjZWlIguv4FSPZhbEff6D_8QUXmdWjlF_XEG2BPMr4",
         "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhbGwiLCJhdWQiOiJGZWxvcmRjbiIsInJvbGVzIjoiW10iLCJpc3MiOiJmZWxvcmQuY24iLCJleHAiOiIyMDIwLTAxLTI2IDExOjMxOjMyIiwiaWF0IjoiMjAxOS0xMC0yOCAxMTozMTozMiIsImp0aSI6IjdmYTBlOWFiYjk5OTRjZGRhNGM5NjI4YzExNGM3YTk4In0.Caj4AAothdUwZAFl8IjcAZmmXHgTt76z8trVG1sf_WHZucFVcHR8FWjShhITpArsQpmokP6GBTMsCvWDl08fUVZBpOWc1CdPUAIIEdArHCFzO64HXc_DLSyg9v0C-qYfxaTlf0npL5QxpBBr9sJcyzxZF3CnpfZpAxm8WZzXG6o",
         "time": "2019-10-28 11:32:11",
         "flag": "success_login"
     },
     "msg": "登錄成功",
     "identifier": ""
 }

我們取 access_token 使用官網jwt.io 提供的解碼功能進行解碼如下:

5.2 登錄失敗結果

 {
     "httpStatus": 401,
     "data": {
         "time": "2019-10-28 12:54:10",
         "flag": "failure_login"
     },
     "msg": "認證失敗",
     "identifier": "-9999"
 }

6. 總結

今天我們將 JWTSpring Security 聯系了起來,實現了 登錄成功后返回 JWT Token 。 這僅僅是一個開始,在下一篇我們將介紹 客戶端如何使用 JWT Token 、服務端如何驗證 JWT Token ,敬請關注。

文章相關的 DEMO 可通過關注公眾號:Felordcn 並回復 ss06 獲取。

關注公眾號:Felordcn獲取更多資訊

個人博客:https://felord.cn


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM