歡迎閱讀 Spring Security 實戰乾貨 系列文章,上一文 咱們實現了 JWT 工具。本篇咱們將一塊兒探討如何將 JWT 與 Spring Security 結合起來,在認證成功後再也不跳轉到指定頁面而是直接返回 JWT Token 。 本文的**DEMO
可經過文末的方式獲取**html
JWT 適用於先後端分離。咱們在登陸成功後不在跳轉到首頁,將會直接返回 JWT Token 對(DEMO中爲JwtTokenPair
),登陸失敗後返回認證失敗相關的信息。前端
若是你看過 Spring Security 實戰乾貨: 玩轉自定義登陸 將很是容易理解下面的作法。java
AuthenticationSuccessHandler
用於處理登陸成功後的邏輯,咱們編寫實現並注入 Spring IoC 容器:spring
/** * 處理登陸成功後返回 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, "登陸成功")); }; }
AuthenticationFailureHandler
處理認證失敗後的邏輯,前端根據此返回進行跳轉處理邏輯,咱們也實現它並注入 Spring IoC 容器:json
/** * 失敗登陸處理器 處理登陸失敗後的邏輯 登陸失敗返回信息 以此爲依據跳轉 * * @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")); }; }
把上面寫好的兩個 Handler Bean 寫入 登陸配置,相關片段以下,詳情參見文末 DEMO:後端
httpSecurity.formLogin().loginProcessingUrl(LOGIN_PROCESSING_URL).successHandler(authenticationSuccessHandler).failureHandler(authenticationFailureHandler)
咱們依然經過 Spring Security 實戰乾貨: 玩轉自定義登陸 一文中章節 6.4 測試 來運行。結果以下:前後端分離
{ "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 提供的解碼功能進行解碼以下:ide
{ "httpStatus": 401, "data": { "time": "2019-10-28 12:54:10", "flag": "failure_login" }, "msg": "認證失敗", "identifier": "-9999" }
今天咱們將 JWT 和 Spring Security 聯繫了起來,實現了 登陸成功後返回 JWT Token 。 這僅僅是一個開始,在下一篇咱們將介紹 客戶端如何使用 JWT Token 、服務端如何驗證 JWT Token ,敬請關注。工具
文章相關的 DEMO 可經過關注公衆號:Felordcn 並回復 ss06
獲取。測試
關注公衆號:Felordcn獲取更多資訊