SpringBoot通過token實現(xiàn)用戶互踢功能(具體實現(xiàn))
認識token
所謂token,既用戶能夠在一定時間內(nèi)證明自己身份的一長串字符串。正常的使用流程為:用戶第一次登入——》服務器為該用戶簽發(fā)一份token——》進行其他服務請求時攜帶上token——》服務器判斷此token在有效期內(nèi)——》放行此次請求。
在上述過程中,用戶只有在請求特定的接口時可以不用攜帶token,例如登入、請求一些基本的公共信息等。
通過token實現(xiàn)用戶互踢
通過上述我們知道,用戶在請求一些接口時需要用到token進行校驗。那么要想通過token實現(xiàn)用戶互踢的功能,其實就變得簡單了。具體思路為:
①:設立一份token白名單
②:同一個賬號多次登入時,新登入的用戶將之前登入的用戶token擠出白名單
這里需要注意的是:token無法主動設置某個token為無效狀態(tài)。這也就意味著,我們需要設置一份白名單或者黑名單。
白名單:只有在白名單內(nèi)的token才算是有效的。
黑名單:在黑名單內(nèi)的token都是無效的。
具體實現(xiàn)
這里我使用的是白名單的方法,之所以使用白名單,是因為使用白名單所占用的空間小,因為一個用戶正在有效的token只會有一個,而其無效的token可能會有多個。具體步驟如下:
1、token的實現(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;
}
}
/**
* 校驗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的實現(xiàn),其中包括了token的簽發(fā),驗證以及根據(jù)token獲取賬號。
2、用戶登入時的方法實現(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,"賬號不存在",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,"賬號/密碼錯誤",null);
}
}從上述代碼可見,當?shù)侨氤晒r,會將上一次登入時留下的token移除白名單,并將最近登入生成的token放入白名單。
3、通過攔截器進行校驗
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獲取用戶賬號
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;
}
}
}
在這里,我們會判斷用戶攜帶的token是否存在于白名單內(nèi),不存在則說明這次攜帶的token是無效的。
4、對攔截器進行注冊并放行登入等接口
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)建用戶攔截器對象并指定其攔截的路徑和排除的路徑
registry.addInterceptor(new Interceptor()).
addPathPatterns("/**").excludePathPatterns("/user/login","/admin/login","/service/getAllServices",
"/shop/getShopById","/img/**");
}
}上述代碼為放行了登入等接口。
總結(jié)
當然,在此次我的白名單使用的是Map存儲的。網(wǎng)絡上也有使用redis的好像,因為我目前并沒有學習redis,大家感興趣的可以試試使用redis。
到此這篇關于SpringBoot通過token實現(xiàn)用戶互踢功能的文章就介紹到這了,更多相關SpringBoot用戶互踢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot項目使用slf4j的MDC日志打點功能(最新推薦)
這篇文章主要介紹了SpringBoot項目使用slf4j的MDC日志打點功能,本文通過示例代碼給大家介紹非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-06-06
java 集合之實現(xiàn)類ArrayList和LinkedList的方法
下面小編就為大家?guī)硪黄猨ava 集合之實現(xiàn)類ArrayList和LinkedList的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10
spring,mybatis事務管理配置與@Transactional注解使用詳解
這篇文章主要介紹了spring,mybatis事務管理配置與@Transactional注解使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07

