這篇文章將為大家詳細(xì)講解有關(guān)spring boot+jwt如何實(shí)現(xiàn)api中token認(rèn)證,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
海陵網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)建站!從網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、APP開(kāi)發(fā)、成都響應(yīng)式網(wǎng)站建設(shè)等網(wǎng)站項(xiàng)目制作,到程序開(kāi)發(fā),運(yùn)營(yíng)維護(hù)。創(chuàng)新互聯(lián)建站2013年開(kāi)創(chuàng)至今到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來(lái)保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)建站。
jwt(json web token)的使用,她主要用來(lái)生成接口訪問(wèn)的token和驗(yàn)證,其單獨(dú)結(jié)合springboot來(lái)開(kāi)發(fā)api接口token驗(yàn)證很是方便,由于jwt的token中存儲(chǔ)有用戶的信息并且有加密,所以適用于分布式,這樣直接吧信息存儲(chǔ)在用戶本地減速了服務(wù)端存儲(chǔ)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來(lái)達(dá)到3種結(jié)果:
生成token
驗(yàn)證token是否有效
獲取token中jwt信息(主要用戶信息)
生成token
引入了jjwt依賴后,要生成token很方便;對(duì)于一個(gè)token來(lái)說(shuō),代表的是唯一并且不可逆的,因此我們?cè)谏蓵r(shí)需要增加一些唯一數(shù)據(jù)進(jìn)去,比如下面的id:
long currentTime = System.currentTimeMillis();
return Jwts.builder()
.setId(UUID.randomUUID().toString())
.setIssuedAt(new Date(currentTime)) //簽發(fā)時(shí)間
.setSubject("system") //說(shuō)明
.setIssuer("shenniu003") //簽發(fā)者信息
.setAudience("custom") //接收用戶
.compressWith(CompressionCodecs.GZIP) //數(shù)據(jù)壓縮方式
.signWith(SignatureAlgorithm.HS256, encryKey) //加密方式
.setExpiration(new Date(currentTime + secondTimeOut * 1000)) //過(guò)期時(shí)間戳
.addClaims(claimMaps) //cla信息
.compact();通過(guò)uuid來(lái)標(biāo)記唯一id信息;當(dāng)然在對(duì)token加密時(shí)需要用到秘鑰,jwt很是方便她支持了很多中加密方式如:HS256,HS265,Md5等復(fù)雜及常用的加密方式;
jwt生成的token中內(nèi)容分為3個(gè)部分:head信息,payload信息,sign信息,通常我們要做的是往payload增加一些用戶信息(比如:賬號(hào),昵稱,權(quán)限等,但不包含密碼);在對(duì)jwt的token有一定了解后,我們來(lái)看下真實(shí)生成的token值:
eyJhbGciOiJIUzI1NiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAAFWMTQ7CIBSE7_LWkPDzaEsP4QnYINCIptX4INE0vbtg4sLlfPPN7HAtGWbwg1BKL4GrcbEcIwpujZF8iiEpjXFapAAG2ReYpUEcR2VxYED13Nb0ppLW3hP1eEnblqsQuiFfY0OhUrl3I70evweU_aFSejZhd7DlcDv5NTmYHUilHTD3rf_hAccHRTv--7YAAAA.i4xwoQtaWI0-dwHWN8uZ4DBm-vfli5bavYU9lRYxU5E
驗(yàn)證token是否有效
token生成的時(shí)都會(huì)伴隨者有一個(gè)失效的時(shí)間,在這我們可以通過(guò)setExpiration函數(shù)設(shè)置過(guò)期時(shí)間,記住jwt的有效時(shí)間不是滑動(dòng)的,也就是說(shuō)不做任何處理時(shí),當(dāng)?shù)竭_(dá)第一次設(shè)置的失效時(shí)間時(shí),就基本沒(méi)用了,要獲取token是否過(guò)期可以使用如下方式:
public static boolean isExpiration(String token, String encryKey) {
try {
return getClaimsBody(token, encryKey)
.getExpiration()
.before(new Date());
} catch (ExpiredJwtException ex) {
return true;
}
}這里使用了date的before來(lái)用獲取的過(guò)期時(shí)間和當(dāng)前時(shí)間對(duì)比,判斷是否繼續(xù)有效,需要注意的是如果在token失效后再通過(guò)getClaimsBody(token, encryKey)獲取信息,此時(shí)會(huì)報(bào)ExpiredJwtException錯(cuò)誤,我們即可認(rèn)為過(guò)期。
獲取token中jwt信息(主要用戶信息)
通常我們要把登錄用戶信息存儲(chǔ)在jwt生成的token中,這里可以通過(guò) addClaims(claimMaps) 傳遞map來(lái)設(shè)置信息,反過(guò)來(lái)要獲取token中的用戶信息,我們需要這樣做:
return Jwts.parser() .setSigningKey(encryKey) .parseClaimsJws(token) .getBody();
此時(shí)body獲取出來(lái)是Claims類型,我們需要從中獲取到用戶信息,需要注意的是在addClaims存儲(chǔ)信息的時(shí)候如果存儲(chǔ)的map值沒(méi)做過(guò)出來(lái),那完整的實(shí)體對(duì)象存儲(chǔ)進(jìn)去后會(huì)映射成一個(gè)LinkHasMap類型,如下:

因此通常會(huì)在存儲(chǔ)的時(shí)候json化,如下代碼:
claimMaps.forEach((key, val) -> {
claimMaps.put(key, JSON.toJSONString(val));
});再來(lái)就是通過(guò)get方法獲取我們存儲(chǔ)進(jìn)去的信息,并json反序列化:
/**
* 獲取body某個(gè)值
*
* @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某個(gè)值,json字符轉(zhuǎn)實(shí)體
*
* @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;
}
}來(lái)到這里一個(gè)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ā)時(shí)間
.setSubject("system") //說(shuō)明
.setIssuer("shenniu003") //簽發(fā)者信息
.setAudience("custom") //接收用戶
.compressWith(CompressionCodecs.GZIP) //數(shù)據(jù)壓縮方式
.signWith(SignatureAlgorithm.HS256, encryKey) //加密方式
.setExpiration(new Date(currentTime + secondTimeOut * 1000)) //過(guò)期時(shí)間戳
.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某個(gè)值
*
* @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某個(gè)值,json字符轉(zhuǎn)實(shí)體
*
* @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;
}
}
/**
* 是否過(guò)期
*
* @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 "";
}
}
}過(guò)濾器驗(yàn)證token
有了基本的JwtUtil工具,我們需要用到springboot項(xiàng)目中,一般來(lái)說(shuō)對(duì)于登錄授權(quán)token驗(yàn)證可以通過(guò)過(guò)濾器來(lái)操作,這里創(chuàng)建一個(gè)AuthenFilter,用于對(duì)post請(qǐng)求過(guò)來(lái)的token做驗(yàn)證:
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("無(wú)token");
return;
}
//jwt驗(yàn)證
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));
}
}
}
}要是自定義過(guò)濾器AuthenFilter生效,還需要把她注冊(cè)到容器中,這里通過(guò)編碼方式,當(dāng)然還可以通過(guò)@WebFilter注解來(lái)加入到容器中:
@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匹配的是過(guò)濾器作用的url連接,根據(jù)需求而定;為了驗(yàn)證效果,這里我創(chuàng)建了兩個(gè)接口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);
}
}最終要獲通過(guò)head傳遞token值來(lái)訪問(wèn)t01接口,得到如下結(jié)果:

token在有效時(shí)間后訪問(wèn)直接失敗,從新獲取token并訪問(wèn)t01接口,得到成功的信息:

關(guān)于“spring boot+jwt如何實(shí)現(xiàn)api中token認(rèn)證”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
文章題目:springboot+jwt如何實(shí)現(xiàn)api中token認(rèn)證
網(wǎng)站鏈接:http://chinadenli.net/article20/jggjco.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站營(yíng)銷(xiāo)、品牌網(wǎng)站設(shè)計(jì)、標(biāo)簽優(yōu)化、面包屑導(dǎo)航、手機(jī)網(wǎng)站建設(shè)、域名注冊(cè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)