後端是springcloud,前端是用react寫的,以前用過session或者redis保存登陸態,聽了一位朋友的推薦,使用jwt作token校驗前端
portal項目負責用戶登陸第三方綁定等用戶相關功能react
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.10.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.10.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.10.5</version>
<scope>runtime</scope>
</dependency>
複製代碼
@Component
@Data
@ConfigurationProperties("jwt")
public class JWTUtil {
private String issuer;
private String subject;
private String audience;
private String alg;
private String typ;
private int expire;
/**
*@author: zh
*@date: 2019-04-28 14:56
*@desc 生成token
*@param
*@return
*/
public String createToken(Map claims) {
try {
Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
Map header=new HashMap();
header.put("alg", alg);
header.put("typ", typ);
Date nowDate = new Date();
Date expireDate = getAfterDate(nowDate,0,0,0,0,expire,0);//30分鐘過時
String token = Jwts.builder()
.setHeader(header)
.setIssuer(issuer)
.setSubject(subject)
.setAudience(audience)
.setClaims(claims)
.setExpiration(expireDate)
.setIssuedAt(nowDate)
.setId(UUID.randomUUID().toString())
.signWith(key)
.compact();
return token;
} catch (JwtException exception){
exception.printStackTrace();
throw new BizException(BizStatu.CREATE_TOKEN_FAILED);
}
}
public Date getAfterDate(Date date, int year, int month, int day, int hour, int minute, int second){
if(date == null){
date = new Date();
}
Calendar cal = new GregorianCalendar();
cal.setTime(date);
if(year != 0){
cal.add(Calendar.YEAR, year);
}
if(month != 0){
cal.add(Calendar.MONTH, month);
}
if(day != 0){
cal.add(Calendar.DATE, day);
}
if(hour != 0){
cal.add(Calendar.HOUR_OF_DAY, hour);
}
if(minute != 0){
cal.add(Calendar.MINUTE, minute);
}
if(second != 0){
cal.add(Calendar.SECOND, second);
}
return cal.getTime();
}
/**
*@author: zh
*@date: 2019-04-28 14:56
*@desc token校驗
*@param
*@return
*/
public void verifyToken(int userId,String token) {
Claims claims=null;
Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
try {
claims = Jwts.parser()
.setSigningKey(key)
.parseClaimsJws(token)
.getBody();
if(claims==null){
throw new BizException(BizStatu.CLAIMS_IS_NOT_DEFINED);
}
if(claims.getAudience()==null||!audience.equals(claims.getAudience())){
throw new BizException(BizStatu.TOKEN_IS_WRONG);
}
if(claims.getIssuer()==null||!issuer.equals(claims.getIssuer())){
throw new BizException(BizStatu.TOKEN_IS_WRONG);
}
if(claims.getSubject()==null||!subject.equals(claims.getSubject())){
throw new BizException(BizStatu.TOKEN_IS_WRONG);
}
if(claims.get("userId")==null||userId!=claims.get("userId",Integer.class)){
throw new BizException(BizStatu.TOKEN_IS_WRONG);
}
if(claims.getExpiration()==null|| DateUtil.compare_date(new Date(),claims.getExpiration())>0){
throw new BizException(BizStatu.TOKEN_EXPIRED);
}
}catch (JwtException ex) {
ex.printStackTrace();
}
}
}
複製代碼
Long userId=user.getLong("id");
Map claims=new HashMap();
claims.put("userId",userId);
String token= jwtUtil.createToken(claims);
複製代碼
@Component
public class TokenFilter implements GatewayFilter, Ordered {
@Autowired
private JWTUtil jwtUtil;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
String token = headers.getFirst("token");
String userId = headers.getFirst("userId");
if (token==null||"".equals(token.trim()) ||userId==null||"".equals(userId.trim()) ) {
throw new BizException(401,"缺乏受權token");
}
long id;
try {
id = Long.parseLong(userId);
}catch (NumberFormatException e){
throw new BizException(BizStatu.USERID_IS_NOT_DEFINED);
}
jwtUtil.verifyToken(id,token);
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
複製代碼
我這個是朋友合做的項目,寫的也很簡單,登陸受權30分鐘,當用戶在20分鐘以後走網關並且token沒到過時時間,這邊會生成一個新的token放入到用戶header,前端這邊寫一個過濾器,當返回的header中有token且與本地token不一致,替換掉本地token。這樣就能夠懶得寫中間件刷新token了,用得少,只是併發測試沒作,還須要多考慮點東西web