gateway和jwt网关认证实现过程解析
这篇文章主要介绍了gateway和jwt网关认证实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
思路:全局过滤器对所有的请求拦截(生成token有效期30分钟,放入redis设置有效期3天。3天之类可以通过刷新接口自动刷新,超过3天需要重新登录。)
前端在调用接口之前先判断token是否过期(3o分钟),过期则先调刷新接口,换取新token,
1引入相关jar
org.springframework.cloud spring-cloud-starter-gateway io.jsonwebtoken jjwt 0.9.0
2编写Jwt工具类(生成token+解析token)
packagespring.cloud.gateway.common;
importjava.text.DateFormat;
importjava.text.SimpleDateFormat;
importjava.util.Calendar;
importjava.util.Date;
importjava.util.HashMap;
importjava.util.Map;
importio.jsonwebtoken.ExpiredJwtException;
importorg.springframework.util.StringUtils;
importio.jsonwebtoken.Jwts;
importio.jsonwebtoken.SignatureAlgorithm;
publicclassJwtUtil{
publicstaticfinalStringSECRET="qazwsx123444$#%#()*&&asdaswwi1235?;!@#kmmmpomin***xx**&";
publicstaticfinalStringTOKEN_PREFIX="Bearer";
publicstaticfinalStringLOGIN_URL="/token/userId/pwd";
publicstaticfinalStringLOGOUT_URL="/token/userId";
publicstaticfinalStringHEADER_AUTH="authorization";
publicstaticfinalStringHEADER_USERID="userid";
//token超时时间
publicstaticfinalintTOKEN_EXPIRATION_MINUTE=30;
//token的redis超时时间
publicstaticfinalintTOKEN_REDIS_EXPIRATION_DAY=7;
publicstaticStringgenerateToken(StringuserId){
Calendarcalendar=Calendar.getInstance();
calendar.add(Calendar.MINUTE,TOKEN_EXPIRATION_MINUTE);//得到前一天
Datedate=calendar.getTime();
DateFormatdf=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");
df.format(date);
//todo优化token的生层规则
HashMapmap=newHashMap<>();
map.put(HEADER_USERID,userId);
Stringjwt=Jwts.builder()
.setSubject(HEADER_USERID).setClaims(map)
.setExpiration(date)
.signWith(SignatureAlgorithm.HS512,SECRET)
.compact();
returnTOKEN_PREFIX+""+jwt;
}
publicstaticMapvalidateToken(Stringtoken){
HashMaptokenMap=newHashMap();
if(StringUtils.isEmpty(token)){
returntokenMap;
}
try{
MaptokenBody=Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token.replace(TOKEN_PREFIX,""))
.getBody();
StringuserId=String.valueOf(tokenBody.get(HEADER_USERID));
tokenMap.put(HEADER_USERID,userId);
}catch(ExpiredJwtExceptione){
e.printStackTrace();
}
returntokenMap;
}
/**
*移到jwtUtil中去
*
*@paramtoken
*@return
*/
publicstaticMapvalidateTokenAndUser(Stringtoken,StringuserIdIn){
MaptokenResultMap=newHashMap<>();
if(StringUtils.isEmpty(token)||StringUtils.isEmpty(userIdIn)){
returntokenResultMap;
}
tokenResultMap=validateToken(token);
if(StringUtils.isEmpty(token)||StringUtils.isEmpty(userIdIn)){
returntokenResultMap;
}
//判断传入的userid和token是否匹配
StringuserIdOri=tokenResultMap.get(HEADER_USERID);
if(!userIdIn.equals(userIdOri)){
returnnewHashMap();
}
returntokenResultMap;
}
}
3编写过滤器类
packagespring.cloud.gateway.filter;
importjava.net.URI;
importjava.util.Map;
importorg.apache.commons.lang.StringUtils;
importorg.springframework.cloud.gateway.filter.GatewayFilterChain;
importorg.springframework.cloud.gateway.filter.GlobalFilter;
importorg.springframework.cloud.gateway.route.Route;
importorg.springframework.cloud.gateway.support.ServerWebExchangeUtils;
importorg.springframework.http.HttpHeaders;
importorg.springframework.http.HttpMethod;
importorg.springframework.http.server.PathContainer;
importorg.springframework.http.server.reactive.ServerHttpRequest;
importorg.springframework.stereotype.Component;
importorg.springframework.web.server.ServerWebExchange;
importreactor.core.publisher.Mono;
importspring.cloud.gateway.common.JwtUtil;
importspring.cloud.gateway.exception.PermissionException;
/**
*参数参考https://blog.csdn.net/tianyaleixiaowu/article/details/83375246
*response参考https://bbs.csdn.net/topics/392412604?list=11074255
*/
@Component
publicclassAuthFilterimplementsGlobalFilter{
@Override
publicMonofilter(ServerWebExchangeexchange,GatewayFilterChainchain){
ServerHttpRequestrequest=exchange.getRequest();
HttpHeadersheader=request.getHeaders();
HttpMethodmethod=request.getMethod();
Stringtoken=header.getFirst(JwtUtil.HEADER_AUTH);
StringuserId=header.getFirst(JwtUtil.HEADER_USERID);
PathContainerpathContainer=request.getPath().pathWithinApplication();
Stringpath=pathContainer.value();
//2-处理登录请求
if(StringUtils.isBlank(token)){
//是登录接口则放行,否则返回异常
if(path.contains(JwtUtil.LOGIN_URL)&&HttpMethod.POST.equals(method)){
thrownewPermissionException("pleaselogin");
}
returnchain.filter(exchange);
}
//3-处理刷新token请求
if(path.indexOf("refresh")>=0){
//放行去掉刷新接口(在刷新前校验userId和token是否匹配)
returnchain.filter(exchange);
}
//4-处理刷新token请求
if(path.contains(JwtUtil.LOGOUT_URL)&&HttpMethod.DELETE.equals(method)){
//放行去掉登出接口(在刷新前校验userId和token是否匹配)
returnchain.filter(exchange);
}
//5-携带token请求其他业务接口
MapvalidateResultMap=JwtUtil.validateTokenAndUser(token,userId);
if(validateResultMap==null||validateResultMap.isEmpty()){
thrownewPermissionException("token已经失效");
}
//TODO将用户信息存放在请求header中传递给下游业务
RoutegatewayUrl=exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
URIuri=gatewayUrl.getUri();
//表示下游请求对应的服务名如SPRING-CLOUD-SERVICESPRING-CLOUD-GATEWAY
StringserviceName=uri.getHost();
ServerHttpRequest.Buildermutate=request.mutate();
mutate.header("x-user-id",validateResultMap.get("userid"));
mutate.header("x-user-name",validateResultMap.get("user"));
mutate.header("x-user-serviceName",serviceName);
ServerHttpRequestbuildReuqest=mutate.build();
//todo如果响应中需要放数据,也可以放在response的header中
//ServerHttpResponseresponse=exchange.getResponse();
//response.getHeaders().add("new_token","token_value");
returnchain.filter(exchange.mutate().request(buildReuqest).build());
}
}
4编写相关接口API
packagespring.cloud.gateway.controller;
importorg.springframework.web.bind.annotation.*;
importspring.cloud.gateway.common.JwtUtil;
importjava.util.Map;
@RestController
@RequestMapping("/token")
publicclassTokenController{
/**
*登录接口
*@paramuser(userID+pwd)
*@return
*/
@PostMapping("/userId/pwd")
publicStringgetToken(@RequestBodyMapuser){
//用户名密码需要加密处理
Stringresult="";
if(user==null||user.isEmpty()){
returnresult;
}
StringuserId=user.get("userId");
Stringpwd=user.get("pwd");
if(!doLogin(userId,pwd)){
returnresult;
}
Stringtoken=JwtUtil.generateToken(userId);
//todo将token放入redis中,设置超时时间为2*t
returntoken;
}
privateBooleandoLogin(StringuserId,Stringpwd){
//后续对接user表验证
if("admin".equals(userId)&&"123".equals(pwd)){
returntrue;
}
if("spring".equals(userId)&&"123".equals(pwd)){
returntrue;
}
if("gateway".equals(userId)&&"123".equals(pwd)){
returntrue;
}
returnfalse;
}
/**
*登出接口
*/
/**
*刷新token的接口
*在刷新前校验userId和token是否匹配
*/
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。