您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關(guān)spring boot+jwt如何實現(xiàn)api中token認證,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
jwt(json web token)的使用,她主要用來生成接口訪問的token和驗證,其單獨結(jié)合springboot來開發(fā)api接口token驗證很是方便,由于jwt的token中存儲有用戶的信息并且有加密,所以適用于分布式,這樣直接吧信息存儲在用戶本地減速了服務端存儲sessiion或token的壓力;
如下快速使用:
<!--jwt--> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.0</version> </dependency> <!--阿里 FastJson依賴--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.44</version> </dependency>
一般使用jwt來達到3種結(jié)果:
生成token
驗證token是否有效
獲取token中jwt信息(主要用戶信息)
生成token
引入了jjwt依賴后,要生成token很方便;對于一個token來說,代表的是唯一并且不可逆的,因此我們在生成時需要增加一些唯一數(shù)據(jù)進去,比如下面的id:
long currentTime = System.currentTimeMillis(); return Jwts.builder() .setId(UUID.randomUUID().toString()) .setIssuedAt(new Date(currentTime)) //簽發(fā)時間 .setSubject("system") //說明 .setIssuer("shenniu003") //簽發(fā)者信息 .setAudience("custom") //接收用戶 .compressWith(CompressionCodecs.GZIP) //數(shù)據(jù)壓縮方式 .signWith(SignatureAlgorithm.HS256, encryKey) //加密方式 .setExpiration(new Date(currentTime + secondTimeOut * 1000)) //過期時間戳 .addClaims(claimMaps) //cla信息 .compact();
通過uuid來標記唯一id信息;當然在對token加密時需要用到秘鑰,jwt很是方便她支持了很多中加密方式如:HS256,HS265,Md5等復雜及常用的加密方式;
jwt生成的token中內(nèi)容分為3個部分:head信息,payload信息,sign信息,通常我們要做的是往payload增加一些用戶信息(比如:賬號,昵稱,權(quán)限等,但不包含密碼);在對jwt的token有一定了解后,我們來看下真實生成的token值:
eyJhbGciOiJIUzI1NiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAAFWMTQ7CIBSE7_LWkPDzaEsP4QnYINCIptX4INE0vbtg4sLlfPPN7HAtGWbwg1BKL4GrcbEcIwpujZF8iiEpjXFapAAG2ReYpUEcR2VxYED13Nb0ppLW3hP1eEnblqsQuiFfY0OhUrl3I70evweU_aFSejZhd7DlcDv5NTmYHUilHTD3rf_hAccHRTv--7YAAAA.i4xwoQtaWI0-dwHWN8uZ4DBm-vfli5bavYU9lRYxU5E
驗證token是否有效
token生成的時都會伴隨者有一個失效的時間,在這我們可以通過setExpiration函數(shù)設(shè)置過期時間,記住jwt的有效時間不是滑動的,也就是說不做任何處理時,當?shù)竭_第一次設(shè)置的失效時間時,就基本沒用了,要獲取token是否過期可以使用如下方式:
public static boolean isExpiration(String token, String encryKey) { try { return getClaimsBody(token, encryKey) .getExpiration() .before(new Date()); } catch (ExpiredJwtException ex) { return true; } }
這里使用了date的before來用獲取的過期時間和當前時間對比,判斷是否繼續(xù)有效,需要注意的是如果在token失效后再通過getClaimsBody(token, encryKey)獲取信息,此時會報ExpiredJwtException錯誤,我們即可認為過期。
獲取token中jwt信息(主要用戶信息)
通常我們要把登錄用戶信息存儲在jwt生成的token中,這里可以通過 addClaims(claimMaps) 傳遞map來設(shè)置信息,反過來要獲取token中的用戶信息,我們需要這樣做:
return Jwts.parser() .setSigningKey(encryKey) .parseClaimsJws(token) .getBody();
此時body獲取出來是Claims類型,我們需要從中獲取到用戶信息,需要注意的是在addClaims存儲信息的時候如果存儲的map值沒做過出來,那完整的實體對象存儲進去后會映射成一個LinkHasMap類型,如下:
因此通常會在存儲的時候json化,如下代碼:
claimMaps.forEach((key, val) -> { claimMaps.put(key, JSON.toJSONString(val)); });
再來就是通過get方法獲取我們存儲進去的信息,并json反序列化:
/** * 獲取body某個值 * * @param token * @param encryKey * @param key * @return */ public static Object getVal(String token, String encryKey, String key) { return getJws(token, encryKey).getBody().get(key); } /** * 獲取body某個值,json字符轉(zhuǎn)實體 * * @param token * @param encryKey * @param key * @param tClass * @param <T> * @return */ public static <T> T getValByT(String token, String encryKey, String key, Class<T> tClass) { try { String strJson = getVal(token, encryKey, key).toString(); return JSON.parseObject(strJson, tClass); } catch (Exception ex) { return null; } }
來到這里一個Jwt的Util代碼基本就完成了,下面給出完整的代碼例子,僅供參考:
public class JwtUtil { /** * 獲取token - json化 map信息 * * @param claimMaps * @param encryKey * @param secondTimeOut * @return */ public static String getTokenByJson(Map<String, Object> claimMaps, String encryKey, int secondTimeOut) { return getToken(claimMaps, true, encryKey, secondTimeOut); } /** * 獲取token * * @param claimMaps * @param isJsonMpas * @param encryKey * @param secondTimeOut * @return */ public static String getToken(Map<String, Object> claimMaps, boolean isJsonMpas, String encryKey, int secondTimeOut) { if (isJsonMpas) { claimMaps.forEach((key, val) -> { claimMaps.put(key, JSON.toJSONString(val)); }); } long currentTime = System.currentTimeMillis(); return Jwts.builder() .setId(UUID.randomUUID().toString()) .setIssuedAt(new Date(currentTime)) //簽發(fā)時間 .setSubject("system") //說明 .setIssuer("shenniu003") //簽發(fā)者信息 .setAudience("custom") //接收用戶 .compressWith(CompressionCodecs.GZIP) //數(shù)據(jù)壓縮方式 .signWith(SignatureAlgorithm.HS256, encryKey) //加密方式 .setExpiration(new Date(currentTime + secondTimeOut * 1000)) //過期時間戳 .addClaims(claimMaps) //cla信息 .compact(); } /** * 獲取token中的claims信息 * * @param token * @param encryKey * @return */ private static Jws<Claims> getJws(String token, String encryKey) { return Jwts.parser() .setSigningKey(encryKey) .parseClaimsJws(token); } public static String getSignature(String token, String encryKey) { try { return getJws(token, encryKey).getSignature(); } catch (Exception ex) { return ""; } } /** * 獲取token中head信息 * * @param token * @param encryKey * @return */ public static JwsHeader getHeader(String token, String encryKey) { try { return getJws(token, encryKey).getHeader(); } catch (Exception ex) { return null; } } /** * 獲取payload body信息 * * @param token * @param encryKey * @return */ public static Claims getClaimsBody(String token, String encryKey) { return getJws(token, encryKey).getBody(); } /** * 獲取body某個值 * * @param token * @param encryKey * @param key * @return */ public static Object getVal(String token, String encryKey, String key) { return getJws(token, encryKey).getBody().get(key); } /** * 獲取body某個值,json字符轉(zhuǎn)實體 * * @param token * @param encryKey * @param key * @param tClass * @param <T> * @return */ public static <T> T getValByT(String token, String encryKey, String key, Class<T> tClass) { try { String strJson = getVal(token, encryKey, key).toString(); return JSON.parseObject(strJson, tClass); } catch (Exception ex) { return null; } } /** * 是否過期 * * @param token * @param encryKey * @return */ public static boolean isExpiration(String token, String encryKey) { try { return getClaimsBody(token, encryKey) .getExpiration() .before(new Date()); } catch (ExpiredJwtException ex) { return true; } } public static String getSubject(String token, String encryKey) { try { return getClaimsBody(token, encryKey).getSubject(); } catch (Exception ex) { return ""; } } }
過濾器驗證token
有了基本的JwtUtil工具,我們需要用到springboot項目中,一般來說對于登錄授權(quán)token驗證可以通過過濾器來操作,這里創(chuàng)建一個AuthenFilter,用于對post請求過來的token做驗證:
public class AuthenFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest rq = (HttpServletRequest) servletRequest; HttpServletResponse rp = (HttpServletResponse) servletResponse; RpBase rpBase = new RpBase(); try { //只接受post if (!rq.getMethod().equalsIgnoreCase("post")) { filterChain.doFilter(servletRequest, servletResponse); return; } String token = rq.getHeader("token"); if (StringUtils.isEmpty(token)) { rpBase.setMsg("無token"); return; } //jwt驗證 MoUser moUser = JwtUtil.getValByT(token, WebConfig.Token_EncryKey, WebConfig.Login_User, MoUser.class); if (moUser == null) { rpBase.setMsg("token已失效"); return; } System.out.println("token用戶:" + moUser.getNickName()); filterChain.doFilter(servletRequest, servletResponse); } catch (Exception ex) { } finally { if (!StringUtils.isEmpty(rpBase.getMsg())) { rp.setCharacterEncoding("utf-8"); rpBase.setCode(HttpStatus.BAD_REQUEST.value()); rp.getWriter().write(JSON.toJSONString(rpBase)); } } } }
要是自定義過濾器AuthenFilter生效,還需要把她注冊到容器中,這里通過編碼方式,當然還可以通過@WebFilter注解來加入到容器中:
@Configuration public class WebFilterConfig { @Bean public FilterRegistrationBean setFilter() { FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(new AuthenFilter()); registrationBean.addUrlPatterns("/api/*"); registrationBean.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE); return registrationBean; } }
注意addUrlPatterns匹配的是過濾器作用的url連接,根據(jù)需求而定;為了驗證效果,這里我創(chuàng)建了兩個接口getToken和t0,分別是獲取token和post查詢接口,代碼如是:
@RestController public class TestController { @PostMapping("/api/t0") public String t0() throws MyException { return UUID.randomUUID().toString(); } @GetMapping("/token/{userName}") public String getToken(@PathVariable String userName) { MoUser moUser = new MoUser(); moUser.setUserName(userName); moUser.setNickName(userName); Map<String, Object> map = new HashMap<>(); map.put(WebConfig.Login_User, moUser); return JwtUtil.getTokenByJson(map, WebConfig.Token_EncryKey, WebConfig.Token_SecondTimeOut); } }
最終要獲通過head傳遞token值來訪問t01接口,得到如下結(jié)果:
token在有效時間后訪問直接失敗,從新獲取token并訪問t01接口,得到成功的信息:
關(guān)于“spring boot+jwt如何實現(xiàn)api中token認證”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。