Getway jwt 单点登录以及刷新token时间
程序员文章站
2022-04-07 18:05:20
Getway jwt 单点登录以及刷新token时间不用nosql或其他1.集成jwtpom依赖: io.jsonwebtoken jjwt 0.9.0 2.jwt工具类packa...
Getway jwt 单点登录以及刷新token时间
不用nosql或其他
1.集成jwt
pom依赖:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
2.jwt工具类
package com.zkhx.uitls;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
/**
* @author kai
* @since 2020
*/
public class JwtUtils {
//设置token过期时间
// public static final long EXPIRE = 1000 * 60 * 60 * 24;
public static final long EXPIRE = 2000 * 60;
//加密秘钥,可以随便写
public static final String KAI_SECRET = "xxxxxxxxxxxxx";
//这个是生成token的方法,参数可多个
public static String getJwtToken(String id, String nickname){
String JwtToken = Jwts.builder()
//这个是头信息
.setHeaderParam("typ", "JWT")
.setHeaderParam("alg", "HS256")
//这里是设置过期时间
.setSubject("kj-user")
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
//设置token的主体信息,存储用户信息
.claim("id", id)
.claim("nickname", nickname)
//.claim("xxx", xxx)
//签发hash 根据KAI_SECRET秘钥 HS256方式生成
.signWith(SignatureAlgorithm.HS256, KAI_SECRET)
.compact();
return JwtToken;
}
/**
* 判断token是否存在与有效
* @param jwtToken
* @return
*/
public static boolean checkToken(String jwtToken) {
if(StringUtils.isEmpty(jwtToken)) return false;
try {
Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 判断token是否存在与有效
* @param request
* @return
*/
public static boolean checkToken(HttpServletRequest request) {
try {
String jwtToken = request.getHeader("token");
if(StringUtils.isEmpty(jwtToken)) return false;
Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);//根据秘钥解析,如果异常,则返回false
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 根据token获取会员id
* @param request
* @return
*/
public static String getMemberIdByJwtToken(HttpServletRequest request) {
String jwtToken = request.getHeader("token");
if(StringUtils.isEmpty(jwtToken)) return "";
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);
Claims claims = claimsJws.getBody();
return (String)claims.get("id");
}
/**
* 根据token获取nickname
* @param request
* @return
*/
public static String getNameByJwtToken(HttpServletRequest request) {
String jwtToken = request.getHeader("token");
if(StringUtils.isEmpty(jwtToken)) return "";
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);
Claims claims = claimsJws.getBody();
return (String)claims.get("nickname");
}
}
用户服务登录获取token
package com.zkhx.dept.controller;
import com.github.pagehelper.PageInfo;
import com.zkhx.dept.service.UserService;
import com.zkhx.entity.UnitEntity;
import com.zkhx.entity.UserEntity;
import com.zkhx.uitls.JwtUtils;
import com.zkhx.uitls.MD5;
import com.zkhx.uitls.ResultCode;
import com.zkhx.uitls.ResultMsg;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @author qinKJ
* @version 1.0
* @date 2020.12.7 11:50
*/
@RestController
@Slf4j
@RequestMapping("/xxx/xxx")
@Api(tags = "",description = "")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/UserController/userLogin")
public ResultMsg userLogin(@RequestParam("username") String username,@RequestParam("password") String password){
try {
UserEntity userEntity=new UserEntity();
userEntity.setPassword(MD5.encrypt(password));
userEntity.setUsername(username);
UserEntity userEntity1 = userService.userLogin(userEntity);
if(userEntity1!=null&&!userEntity1.equals("")){
String jwtToken = JwtUtils.getJwtToken(String.valueOf(userEntity1.getId()), userEntity1.getUsername());
return ResultMsg.successMsg().data(jwtToken);
}else {
return ResultMsg.failMsg(ResultCode.DATANULL,"登录失败,请检查用户名和密码是否正确");
}
}catch (Exception e){
return ResultMsg.failMsg(ResultCode.ERROR,"发生异常");
}
}
}
getway服务
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>${boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>${boot-version}</version>
</dependency>
<!--jwt-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
getway与web是有冲突的,servlet不能用,用 的ServerHttpRequest ServerHttpResponse
原jwt工具类是涉及到servlet的,复制改造jwt工具类到网关服务
package com.zkhx.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.util.StringUtils;
import java.util.Date;
/**
* @author qinKJ
* @version 1.0
* @date 2020.12.30 10:55
*/
public class JwtUtil {
public static final String KAI_SECRET = "xxxxx";
//设置token过期时间
// public static final long EXPIRE = 1000 * 60 * 60 * 24;
public static final long EXPIRE = 2000 * 60;
//这个是生成token的方法,参数可多个
public static String getJwtToken(String id, String nickname){
String JwtToken = Jwts.builder()
//这个是头信息
.setHeaderParam("typ", "JWT")
.setHeaderParam("alg", "HS256")
//这里是设置过期时间
.setSubject("kj-user")
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
//设置token的主体信息,存储用户信息
.claim("id", id)
.claim("nickname", nickname)
//.claim("xxx", xxx)
//签发hash 根据KAI_SECRET秘钥 HS256方式生成
.signWith(SignatureAlgorithm.HS256, KAI_SECRET)
.compact();
return JwtToken;
}
/**
* 判断token是否存在与有效
* @param jwtToken
* @return
*/
public static boolean checkToken(String jwtToken) {
if(StringUtils.isEmpty(jwtToken)) return false;
try {
Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 根据token获取nickname
* @param jwtToken
* @return
*/
public static String getNameByJwtToken(String jwtToken) {
if(StringUtils.isEmpty(jwtToken)) return "";
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);
Claims claims = claimsJws.getBody();
return (String)claims.get("nickname");
}
/**
* 根据token获取会员id
* @param jwtToken
* @return
*/
public static String getMemberIdByJwtToken(String jwtToken) {
if(StringUtils.isEmpty(jwtToken)) return "";
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);
Claims claims = claimsJws.getBody();
return (String)claims.get("id");
}
/**
* 判断是可以刷新token,根据自己的业务来
* @param token
* @param lastPasswordReset
* @return
*/
public static Boolean canTokenBeRefreshed(String token, Date xxx) {
Claims claims;
try {
claims = Jwts.parser()
.setSigningKey(KAI_SECRET)
.parseClaimsJws(token)
.getBody();
final Date iat = claims.getIssuedAt();
final Date exp = claims.getExpiration();
if (iat.before(xxx) || exp.before(new Date())) {
return false;
}
return true;
} catch (Exception e) {
return false;
}
}
/**
* 刷新token
* @param token
* @param id
* @param nickname
* @return
*/
public static String refreshToken(String token,String id, String nickname) {
String refreshedToken;
try {
final Claims claims = Jwts.parser()
.setSigningKey(KAI_SECRET)
.parseClaimsJws(token)
.getBody();
refreshedToken = getJwtToken(id, nickname);
} catch (Exception e) {
refreshedToken = null;
}
return refreshedToken;
}
}
网关拦截器
package com.zkhx.filter;
import com.google.gson.JsonObject;
import com.zkhx.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
/**
* @author qinKJ
* @version 1.0
* @date 2020.12.30 9:50
*/
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
private AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
ServerHttpResponse response = exchange.getResponse();
//校验用户必须登录
if(antPathMatcher.match("/phm/fault/**", path)) {
List<String> tokenList = request.getHeaders().get("token");
String tokenJwt=request.getHeaders().getFirst("token");
if(null == tokenList) {
// ServerHttpResponse response = exchange.getResponse();
return out(response);
} else if(JwtUtil.checkToken(tokenJwt)) {
String nameByJwtToken = JwtUtil.getNameByJwtToken(tokenJwt);
String memberIdByJwtToken = JwtUtil.getMemberIdByJwtToken(tokenJwt);
****************************************************************测试用****************************************************************
Claims claims1 = Jwts.parser()
.setSigningKey("ukc8BDbRigUDaY6pZFfWus2jZWLPHO")
.parseClaimsJws(tokenJwt)
.getBody();
Date d1 = claims1.getIssuedAt();
Date d2 = claims1.getExpiration();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
System.out.println("username参数值:" + claims1.get("username"));
System.out.println("登录用户的id:" + claims1.getId());
System.out.println("登录用户的名称:" + claims1.getSubject());
System.out.println("令牌签发时间:" + sdf.format(d1));
System.out.println("令牌过期时间:" + sdf.format(d2));
Boolean aBoolean = JwtUtil.canTokenBeRefreshed(tokenJwt, new Date());
if (!aBoolean){
tokenJwt=JwtUtil.refreshToken(tokenJwt,memberIdByJwtToken,nameByJwtToken);
Claims claims2 = Jwts.parser()
.setSigningKey(JwtUtil.KAI_SECRET)
.parseClaimsJws(tokenJwt)
.getBody();
Date d3 = claims2.getIssuedAt();
Date d4 = claims2.getExpiration();
System.out.println("username参数值:" + claims2.get("username"));
System.out.println("登录用户的id:" + claims2.getId());
System.out.println("登录用户的名称:" + claims2.getSubject());
System.out.println("令牌签发时间:" + sdf.format(d3));
System.out.println("令牌过期时间:" + sdf.format(d4));
// 获取响应Header,目前的实现中返回的是HttpHeaders实例,可以直接修改
response.getHeaders().add("new_token",tokenJwt);
}
****************************************************************测试用****************************************************************
// TODO 将token信息存放在请求header中传递给下游业务
ServerHttpRequest.Builder mutate = request.mutate();
mutate.header("AuthToken", tokenJwt);
ServerHttpRequest buildReuqest = mutate.build();
return chain.filter(exchange.mutate()
.request(buildReuqest)
.response(response)
.build());
}else {
// ServerHttpResponse response = exchange.getResponse();
return out(response);
}
}
//内部服务接口,不允许外部访问
if(antPathMatcher.match("/**/knowledge/**", path)) {
// ServerHttpResponse response = exchange.getResponse();
return out(response);
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
private Mono<Void> out(ServerHttpResponse response) {
JsonObject message = new JsonObject();
message.addProperty("success", false);
message.addProperty("code", 28004);
message.addProperty("data", "鉴权失败");
byte[] bits = message.toString().getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = response.bufferFactory().wrap(bits);
//response.setStatusCode(HttpStatus.UNAUTHORIZED);
//指定编码,否则在浏览器中会中文乱码
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
return response.writeWith(Mono.just(buffer));
}
}
接下来是给访问服务加过滤
package com.zkhx.config;
/**
* @author qinKJ
* @version 1.0
* @date 2020.12.30 14:13
*/
import com.zkhx.filter.TokenInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.List;
/**
* 拦截器配置
*/
@Configuration
public class InterCepTerConfig implements WebMvcConfigurer {
private TokenInterceptor tokenInterceptor;
//构造方法
public InterCepTerConfig(TokenInterceptor tokenInterceptor){
this.tokenInterceptor = tokenInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry){
List<String> excludePath = new ArrayList<>();
// excludePath.add("/user_register"); //注册
// excludePath.add("/login"); //登录
// excludePath.add("/logout"); //登出
// excludePath.add("/static/**"); //静态资源
// excludePath.add("/swagger-ui.html/**"); //静态资源
// excludePath.add("/assets/**"); //静态资源
registry.addInterceptor(tokenInterceptor)
.addPathPatterns("/**")
.excludePathPatterns(excludePath);
WebMvcConfigurer.super.addInterceptors(registry);
}
/**
* 跨域支持
*
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH", "OPTIONS", "HEAD")
.maxAge(3600 * 24);
}
}
package com.zkhx.filter;
import com.alibaba.fastjson.JSONObject;
import com.zkhx.uitls.JwtUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author qinKJ
* @version 1.0
* @date 2020.12.30 14:07
* 防止直接访问
*/
@Component
public class TokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception{
if(request.getMethod().equals("OPTIONS")){
response.setStatus(HttpServletResponse.SC_OK);
return true;
}
response.setCharacterEncoding("utf-8");
String token = request.getHeader("AuthToken");
if(token != null){
boolean result = JwtUtils.checkToken(token);
if(result){
return true;
}
}
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
PrintWriter out = null;
try{
JSONObject json = new JSONObject();
json.put("success","false");
json.put("msg","不能从这里访问哟");
json.put("code","50000");
response.getWriter().append(json.toJSONString());
System.out.println("认证失败,未通过拦截器");
// response.getWriter().write("50000");
}catch (Exception e){
e.printStackTrace();
response.sendError(500);
return false;
}
return false;
}
}
完毕,不通过网关访问接口:
登录服务获取到token,通过postman调试
替换token后再次访问
刷新成功
本文地址:https://blog.csdn.net/Helloworld_pang/article/details/111993719