SpringBoot通過token實(shí)現(xiàn)用戶互踢功能(具體實(shí)現(xiàn))
認(rèn)識(shí)token
所謂token,既用戶能夠在一定時(shí)間內(nèi)證明自己身份的一長(zhǎng)串字符串。正常的使用流程為:用戶第一次登入——》服務(wù)器為該用戶簽發(fā)一份token——》進(jìn)行其他服務(wù)請(qǐng)求時(shí)攜帶上token——》服務(wù)器判斷此token在有效期內(nèi)——》放行此次請(qǐng)求。
在上述過程中,用戶只有在請(qǐng)求特定的接口時(shí)可以不用攜帶token,例如登入、請(qǐng)求一些基本的公共信息等。
通過token實(shí)現(xiàn)用戶互踢
通過上述我們知道,用戶在請(qǐng)求一些接口時(shí)需要用到token進(jìn)行校驗(yàn)。那么要想通過token實(shí)現(xiàn)用戶互踢的功能,其實(shí)就變得簡(jiǎn)單了。具體思路為:
①:設(shè)立一份token白名單
②:同一個(gè)賬號(hào)多次登入時(shí),新登入的用戶將之前登入的用戶token擠出白名單
這里需要注意的是:token無法主動(dòng)設(shè)置某個(gè)token為無效狀態(tài)。這也就意味著,我們需要設(shè)置一份白名單或者黑名單。
白名單:只有在白名單內(nèi)的token才算是有效的。
黑名單:在黑名單內(nèi)的token都是無效的。
具體實(shí)現(xiàn)
這里我使用的是白名單的方法,之所以使用白名單,是因?yàn)槭褂冒酌麊嗡加玫目臻g小,因?yàn)橐粋€(gè)用戶正在有效的token只會(huì)有一個(gè),而其無效的token可能會(huì)有多個(gè)。具體步驟如下:
1、token的實(shí)現(xiàn)
package org.example.untils; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.exceptions.JWTVerificationException; import java.util.Date; import java.util.HashMap; import java.util.Map; public class Token { /** * 過期30分鐘 * */ private static final long EXPIRE_TIME = 30 * 60 * 1000; /** * jwt密鑰 * */ private static final String SECRET = "jwt_secret"; public static Map<String,String> map=new HashMap<>();//存放token的map集合 public static Map<String, String> getMap() { return map; } public static void setMap(Map<String, String> map) { Token.map = map; } /** * 生成jwt字符串,30分鐘后過期 JWT(json web token) * @param account * @return * */ public static String sign(String account) {//簽發(fā)token try { Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME); Algorithm algorithm = Algorithm.HMAC256(SECRET); return JWT.create() //將account保存到token里面 .withAudience(account) //五分鐘后token過期 .withExpiresAt(date) //token的密鑰 .sign(algorithm); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 根據(jù)token獲取account * @param token * @return * */ public static String getAccount(String token) { try { String account = JWT.decode(token).getAudience().get(0); return account; }catch (JWTDecodeException e) { return null; } } /** * 校驗(yàn)token * @param token * @return * */ public static boolean checkSign(String token) { try { Algorithm algorithm = Algorithm.HMAC256(SECRET); JWTVerifier verifier = JWT.require(algorithm) //.withClaim("username, username) .build(); verifier.verify(token); return true; } catch (JWTVerificationException e) { System.out.println("token無效"); String account=Token.getAccount(token);//將該token從白名單內(nèi)移除 if(account!=null){ Token.map.remove(account);//移出白名單 } return false;//token無效 } } }
上述為token的實(shí)現(xiàn),其中包括了token的簽發(fā),驗(yàn)證以及根據(jù)token獲取賬號(hào)。
2、用戶登入時(shí)的方法實(shí)現(xiàn)
@GetMapping("/login")//用戶登入 public Result login(@Param("account") String account,@Param("password") String password){ User user = userServiceImpl.login(account); if (user==null){ return new Result(201,"賬號(hào)不存在",null); } else if(user.getPassword().equals(password)){//密碼正確 Token.map.remove(account);//移除之前的token String token=Token.sign(account);//簽發(fā)新的token Token.map.put(account,token);//將新的token移入有效token user.setPassword(""); return new Result(200,token,user); } else { return new Result(201,"賬號(hào)/密碼錯(cuò)誤",null); } }
從上述代碼可見,當(dāng)?shù)侨氤晒r(shí),會(huì)將上一次登入時(shí)留下的token移除白名單,并將最近登入生成的token放入白名單。
3、通過攔截器進(jìn)行校驗(yàn)
package org.example.untils; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Objects; public class Interceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token=request.getHeader("token"); String account=Token.getAccount(token);//通過token獲取用戶賬號(hào) String usingToken=Token.map.get(account);//獲取該用戶最新的有效token if(!Objects.equals(token, usingToken)){//該token已經(jīng)失效 response.setStatus(401); return false; } //檢查token if(Token.checkSign(token)){ return true; } else { response.setStatus(401); return false; } } }
在這里,我們會(huì)判斷用戶攜帶的token是否存在于白名單內(nèi),不存在則說明這次攜帶的token是無效的。
4、對(duì)攔截器進(jìn)行注冊(cè)并放行登入等接口
package org.example.untils; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration//定義此類為配置類 public class InterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { //創(chuàng)建用戶攔截器對(duì)象并指定其攔截的路徑和排除的路徑 registry.addInterceptor(new Interceptor()). addPathPatterns("/**").excludePathPatterns("/user/login","/admin/login","/service/getAllServices", "/shop/getShopById","/img/**"); } }
上述代碼為放行了登入等接口。
總結(jié)
當(dāng)然,在此次我的白名單使用的是Map存儲(chǔ)的。網(wǎng)絡(luò)上也有使用redis的好像,因?yàn)槲夷壳安]有學(xué)習(xí)redis,大家感興趣的可以試試使用redis。
到此這篇關(guān)于SpringBoot通過token實(shí)現(xiàn)用戶互踢功能的文章就介紹到這了,更多相關(guān)SpringBoot用戶互踢內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot項(xiàng)目使用slf4j的MDC日志打點(diǎn)功能(最新推薦)
這篇文章主要介紹了SpringBoot項(xiàng)目使用slf4j的MDC日志打點(diǎn)功能,本文通過示例代碼給大家介紹非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06Java設(shè)計(jì)模式之Prototype原型模式
這篇文章主要為大家詳細(xì)介紹了Java設(shè)計(jì)模式之Prototype原型模式的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03深入理解Java動(dòng)態(tài)代理與靜態(tài)代理
這篇文章主要介紹了深入理解Java動(dòng)態(tài)代理與靜態(tài)代理,靜態(tài)代理,代理類和被代理的類實(shí)現(xiàn)了同樣的接口,代理類同時(shí)持有被代理類的引用,動(dòng)態(tài)代理的根據(jù)實(shí)現(xiàn)方式的不同可以分為JDK動(dòng)態(tài)代理和CGlib動(dòng)態(tài)代理2022-06-06java 集合之實(shí)現(xiàn)類ArrayList和LinkedList的方法
下面小編就為大家?guī)硪黄猨ava 集合之實(shí)現(xiàn)類ArrayList和LinkedList的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10spring,mybatis事務(wù)管理配置與@Transactional注解使用詳解
這篇文章主要介紹了spring,mybatis事務(wù)管理配置與@Transactional注解使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07Spring Boot超詳細(xì)講解請(qǐng)求處理流程機(jī)制
SpringBoot是一種整合Spring技術(shù)棧的方式(或者說是框架),同時(shí)也是簡(jiǎn)化Spring的一種快速開發(fā)的腳手架,本篇讓我們一起分析請(qǐng)求處理流程機(jī)制2022-07-07