Getway jwt 单点登录以及刷新token时间

超、凢脫俗 2023-01-01 01:57 240阅读 0赞

Getway jwt 单点登录以及刷新token时间

不用nosql或其他
1.集成jwt
pom依赖:

  1. <dependency>
  2. <groupId>io.jsonwebtoken</groupId>
  3. <artifactId>jjwt</artifactId>
  4. <version>0.9.0</version>
  5. </dependency>

2.jwt工具类

  1. package com.zkhx.uitls;
  2. import io.jsonwebtoken.Claims;
  3. import io.jsonwebtoken.Jws;
  4. import io.jsonwebtoken.Jwts;
  5. import io.jsonwebtoken.SignatureAlgorithm;
  6. import org.springframework.util.StringUtils;
  7. import javax.servlet.http.HttpServletRequest;
  8. import java.util.Date;
  9. /**
  10. * @author kai
  11. * @since 2020
  12. */
  13. public class JwtUtils {
  14. //设置token过期时间
  15. // public static final long EXPIRE = 1000 * 60 * 60 * 24;
  16. public static final long EXPIRE = 2000 * 60;
  17. //加密秘钥,可以随便写
  18. public static final String KAI_SECRET = "xxxxxxxxxxxxx";
  19. //这个是生成token的方法,参数可多个
  20. public static String getJwtToken(String id, String nickname){
  21. String JwtToken = Jwts.builder()
  22. //这个是头信息
  23. .setHeaderParam("typ", "JWT")
  24. .setHeaderParam("alg", "HS256")
  25. //这里是设置过期时间
  26. .setSubject("kj-user")
  27. .setIssuedAt(new Date())
  28. .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
  29. //设置token的主体信息,存储用户信息
  30. .claim("id", id)
  31. .claim("nickname", nickname)
  32. //.claim("xxx", xxx)
  33. //签发hash 根据KAI_SECRET秘钥 HS256方式生成
  34. .signWith(SignatureAlgorithm.HS256, KAI_SECRET)
  35. .compact();
  36. return JwtToken;
  37. }
  38. /**
  39. * 判断token是否存在与有效
  40. * @param jwtToken
  41. * @return
  42. */
  43. public static boolean checkToken(String jwtToken) {
  44. if(StringUtils.isEmpty(jwtToken)) return false;
  45. try {
  46. Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);
  47. } catch (Exception e) {
  48. e.printStackTrace();
  49. return false;
  50. }
  51. return true;
  52. }
  53. /**
  54. * 判断token是否存在与有效
  55. * @param request
  56. * @return
  57. */
  58. public static boolean checkToken(HttpServletRequest request) {
  59. try {
  60. String jwtToken = request.getHeader("token");
  61. if(StringUtils.isEmpty(jwtToken)) return false;
  62. Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);//根据秘钥解析,如果异常,则返回false
  63. } catch (Exception e) {
  64. e.printStackTrace();
  65. return false;
  66. }
  67. return true;
  68. }
  69. /**
  70. * 根据token获取会员id
  71. * @param request
  72. * @return
  73. */
  74. public static String getMemberIdByJwtToken(HttpServletRequest request) {
  75. String jwtToken = request.getHeader("token");
  76. if(StringUtils.isEmpty(jwtToken)) return "";
  77. Jws<Claims> claimsJws = Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);
  78. Claims claims = claimsJws.getBody();
  79. return (String)claims.get("id");
  80. }
  81. /**
  82. * 根据token获取nickname
  83. * @param request
  84. * @return
  85. */
  86. public static String getNameByJwtToken(HttpServletRequest request) {
  87. String jwtToken = request.getHeader("token");
  88. if(StringUtils.isEmpty(jwtToken)) return "";
  89. Jws<Claims> claimsJws = Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);
  90. Claims claims = claimsJws.getBody();
  91. return (String)claims.get("nickname");
  92. }
  93. }

用户服务登录获取token

  1. package com.zkhx.dept.controller;
  2. import com.github.pagehelper.PageInfo;
  3. import com.zkhx.dept.service.UserService;
  4. import com.zkhx.entity.UnitEntity;
  5. import com.zkhx.entity.UserEntity;
  6. import com.zkhx.uitls.JwtUtils;
  7. import com.zkhx.uitls.MD5;
  8. import com.zkhx.uitls.ResultCode;
  9. import com.zkhx.uitls.ResultMsg;
  10. import io.swagger.annotations.Api;
  11. import lombok.extern.slf4j.Slf4j;
  12. import org.springframework.beans.factory.annotation.Autowired;
  13. import org.springframework.web.bind.annotation.*;
  14. /**
  15. * @author qinKJ
  16. * @version 1.0
  17. * @date 2020.12.7 11:50
  18. */
  19. @RestController
  20. @Slf4j
  21. @RequestMapping("/xxx/xxx")
  22. @Api(tags = "",description = "")
  23. public class UserController {
  24. @Autowired
  25. private UserService userService;
  26. @GetMapping("/UserController/userLogin")
  27. public ResultMsg userLogin(@RequestParam("username") String username,@RequestParam("password") String password){
  28. try {
  29. UserEntity userEntity=new UserEntity();
  30. userEntity.setPassword(MD5.encrypt(password));
  31. userEntity.setUsername(username);
  32. UserEntity userEntity1 = userService.userLogin(userEntity);
  33. if(userEntity1!=null&&!userEntity1.equals("")){
  34. String jwtToken = JwtUtils.getJwtToken(String.valueOf(userEntity1.getId()), userEntity1.getUsername());
  35. return ResultMsg.successMsg().data(jwtToken);
  36. }else {
  37. return ResultMsg.failMsg(ResultCode.DATANULL,"登录失败,请检查用户名和密码是否正确");
  38. }
  39. }catch (Exception e){
  40. return ResultMsg.failMsg(ResultCode.ERROR,"发生异常");
  41. }
  42. }
  43. }

在这里插入图片描述
getway服务
依赖

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-gateway</artifactId>
  4. <version>${boot-version}</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-starter-actuator</artifactId>
  9. <version>${boot-version}</version>
  10. </dependency>
  11. <!--jwt-->
  12. <dependency>
  13. <groupId>io.jsonwebtoken</groupId>
  14. <artifactId>jjwt</artifactId>
  15. <version>0.9.0</version>
  16. </dependency>

getway与web是有冲突的,servlet不能用,用 的ServerHttpRequest ServerHttpResponse
原jwt工具类是涉及到servlet的,复制改造jwt工具类到网关服务

  1. package com.zkhx.utils;
  2. import io.jsonwebtoken.Claims;
  3. import io.jsonwebtoken.Jws;
  4. import io.jsonwebtoken.Jwts;
  5. import io.jsonwebtoken.SignatureAlgorithm;
  6. import org.springframework.util.StringUtils;
  7. import java.util.Date;
  8. /**
  9. * @author qinKJ
  10. * @version 1.0
  11. * @date 2020.12.30 10:55
  12. */
  13. public class JwtUtil {
  14. public static final String KAI_SECRET = "xxxxx";
  15. //设置token过期时间
  16. // public static final long EXPIRE = 1000 * 60 * 60 * 24;
  17. public static final long EXPIRE = 2000 * 60;
  18. //这个是生成token的方法,参数可多个
  19. public static String getJwtToken(String id, String nickname){
  20. String JwtToken = Jwts.builder()
  21. //这个是头信息
  22. .setHeaderParam("typ", "JWT")
  23. .setHeaderParam("alg", "HS256")
  24. //这里是设置过期时间
  25. .setSubject("kj-user")
  26. .setIssuedAt(new Date())
  27. .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
  28. //设置token的主体信息,存储用户信息
  29. .claim("id", id)
  30. .claim("nickname", nickname)
  31. //.claim("xxx", xxx)
  32. //签发hash 根据KAI_SECRET秘钥 HS256方式生成
  33. .signWith(SignatureAlgorithm.HS256, KAI_SECRET)
  34. .compact();
  35. return JwtToken;
  36. }
  37. /**
  38. * 判断token是否存在与有效
  39. * @param jwtToken
  40. * @return
  41. */
  42. public static boolean checkToken(String jwtToken) {
  43. if(StringUtils.isEmpty(jwtToken)) return false;
  44. try {
  45. Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);
  46. } catch (Exception e) {
  47. e.printStackTrace();
  48. return false;
  49. }
  50. return true;
  51. }
  52. /**
  53. * 根据token获取nickname
  54. * @param jwtToken
  55. * @return
  56. */
  57. public static String getNameByJwtToken(String jwtToken) {
  58. if(StringUtils.isEmpty(jwtToken)) return "";
  59. Jws<Claims> claimsJws = Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);
  60. Claims claims = claimsJws.getBody();
  61. return (String)claims.get("nickname");
  62. }
  63. /**
  64. * 根据token获取会员id
  65. * @param jwtToken
  66. * @return
  67. */
  68. public static String getMemberIdByJwtToken(String jwtToken) {
  69. if(StringUtils.isEmpty(jwtToken)) return "";
  70. Jws<Claims> claimsJws = Jwts.parser().setSigningKey(KAI_SECRET).parseClaimsJws(jwtToken);
  71. Claims claims = claimsJws.getBody();
  72. return (String)claims.get("id");
  73. }
  74. /**
  75. * 判断是可以刷新token,根据自己的业务来
  76. * @param token
  77. * @param lastPasswordReset
  78. * @return
  79. */
  80. public static Boolean canTokenBeRefreshed(String token, Date xxx) {
  81. Claims claims;
  82. try {
  83. claims = Jwts.parser()
  84. .setSigningKey(KAI_SECRET)
  85. .parseClaimsJws(token)
  86. .getBody();
  87. final Date iat = claims.getIssuedAt();
  88. final Date exp = claims.getExpiration();
  89. if (iat.before(xxx) || exp.before(new Date())) {
  90. return false;
  91. }
  92. return true;
  93. } catch (Exception e) {
  94. return false;
  95. }
  96. }
  97. /**
  98. * 刷新token
  99. * @param token
  100. * @param id
  101. * @param nickname
  102. * @return
  103. */
  104. public static String refreshToken(String token,String id, String nickname) {
  105. String refreshedToken;
  106. try {
  107. final Claims claims = Jwts.parser()
  108. .setSigningKey(KAI_SECRET)
  109. .parseClaimsJws(token)
  110. .getBody();
  111. refreshedToken = getJwtToken(id, nickname);
  112. } catch (Exception e) {
  113. refreshedToken = null;
  114. }
  115. return refreshedToken;
  116. }
  117. }

网关拦截器

  1. package com.zkhx.filter;
  2. import com.google.gson.JsonObject;
  3. import com.zkhx.utils.JwtUtil;
  4. import io.jsonwebtoken.Claims;
  5. import io.jsonwebtoken.Jwts;
  6. import org.springframework.cloud.gateway.filter.GatewayFilterChain;
  7. import org.springframework.cloud.gateway.filter.GlobalFilter;
  8. import org.springframework.core.Ordered;
  9. import org.springframework.core.io.buffer.DataBuffer;
  10. import org.springframework.http.HttpRequest;
  11. import org.springframework.http.server.reactive.ServerHttpRequest;
  12. import org.springframework.http.server.reactive.ServerHttpResponse;
  13. import org.springframework.stereotype.Component;
  14. import org.springframework.util.AntPathMatcher;
  15. import org.springframework.web.server.ServerWebExchange;
  16. import reactor.core.publisher.Mono;
  17. import java.nio.charset.StandardCharsets;
  18. import java.text.SimpleDateFormat;
  19. import java.util.Date;
  20. import java.util.List;
  21. /**
  22. * @author qinKJ
  23. * @version 1.0
  24. * @date 2020.12.30 9:50
  25. */
  26. @Component
  27. public class AuthGlobalFilter implements GlobalFilter, Ordered {
  28. private AntPathMatcher antPathMatcher = new AntPathMatcher();
  29. @Override
  30. public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  31. ServerHttpRequest request = exchange.getRequest();
  32. String path = request.getURI().getPath();
  33. ServerHttpResponse response = exchange.getResponse();
  34. //校验用户必须登录
  35. if(antPathMatcher.match("/phm/fault/**", path)) {
  36. List<String> tokenList = request.getHeaders().get("token");
  37. String tokenJwt=request.getHeaders().getFirst("token");
  38. if(null == tokenList) {
  39. // ServerHttpResponse response = exchange.getResponse();
  40. return out(response);
  41. } else if(JwtUtil.checkToken(tokenJwt)) {
  42. String nameByJwtToken = JwtUtil.getNameByJwtToken(tokenJwt);
  43. String memberIdByJwtToken = JwtUtil.getMemberIdByJwtToken(tokenJwt);
  44. ****************************************************************测试用****************************************************************
  45. Claims claims1 = Jwts.parser()
  46. .setSigningKey("ukc8BDbRigUDaY6pZFfWus2jZWLPHO")
  47. .parseClaimsJws(tokenJwt)
  48. .getBody();
  49. Date d1 = claims1.getIssuedAt();
  50. Date d2 = claims1.getExpiration();
  51. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
  52. System.out.println("username参数值:" + claims1.get("username"));
  53. System.out.println("登录用户的id:" + claims1.getId());
  54. System.out.println("登录用户的名称:" + claims1.getSubject());
  55. System.out.println("令牌签发时间:" + sdf.format(d1));
  56. System.out.println("令牌过期时间:" + sdf.format(d2));
  57. Boolean aBoolean = JwtUtil.canTokenBeRefreshed(tokenJwt, new Date());
  58. if (!aBoolean){
  59. tokenJwt=JwtUtil.refreshToken(tokenJwt,memberIdByJwtToken,nameByJwtToken);
  60. Claims claims2 = Jwts.parser()
  61. .setSigningKey(JwtUtil.KAI_SECRET)
  62. .parseClaimsJws(tokenJwt)
  63. .getBody();
  64. Date d3 = claims2.getIssuedAt();
  65. Date d4 = claims2.getExpiration();
  66. System.out.println("username参数值:" + claims2.get("username"));
  67. System.out.println("登录用户的id:" + claims2.getId());
  68. System.out.println("登录用户的名称:" + claims2.getSubject());
  69. System.out.println("令牌签发时间:" + sdf.format(d3));
  70. System.out.println("令牌过期时间:" + sdf.format(d4));
  71. // 获取响应Header,目前的实现中返回的是HttpHeaders实例,可以直接修改
  72. response.getHeaders().add("new_token",tokenJwt);
  73. }
  74. ****************************************************************测试用****************************************************************
  75. // TODO 将token信息存放在请求header中传递给下游业务
  76. ServerHttpRequest.Builder mutate = request.mutate();
  77. mutate.header("AuthToken", tokenJwt);
  78. ServerHttpRequest buildReuqest = mutate.build();
  79. return chain.filter(exchange.mutate()
  80. .request(buildReuqest)
  81. .response(response)
  82. .build());
  83. }else {
  84. // ServerHttpResponse response = exchange.getResponse();
  85. return out(response);
  86. }
  87. }
  88. //内部服务接口,不允许外部访问
  89. if(antPathMatcher.match("/**/knowledge/**", path)) {
  90. // ServerHttpResponse response = exchange.getResponse();
  91. return out(response);
  92. }
  93. return chain.filter(exchange);
  94. }
  95. @Override
  96. public int getOrder() {
  97. return 0;
  98. }
  99. private Mono<Void> out(ServerHttpResponse response) {
  100. JsonObject message = new JsonObject();
  101. message.addProperty("success", false);
  102. message.addProperty("code", 28004);
  103. message.addProperty("data", "鉴权失败");
  104. byte[] bits = message.toString().getBytes(StandardCharsets.UTF_8);
  105. DataBuffer buffer = response.bufferFactory().wrap(bits);
  106. //response.setStatusCode(HttpStatus.UNAUTHORIZED);
  107. //指定编码,否则在浏览器中会中文乱码
  108. response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
  109. return response.writeWith(Mono.just(buffer));
  110. }
  111. }

接下来是给访问服务加过滤
在这里插入图片描述

  1. package com.zkhx.config;
  2. /**
  3. * @author qinKJ
  4. * @version 1.0
  5. * @date 2020.12.30 14:13
  6. */
  7. import com.zkhx.filter.TokenInterceptor;
  8. import org.springframework.context.annotation.Configuration;
  9. import org.springframework.web.servlet.config.annotation.CorsRegistry;
  10. import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
  11. import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  12. import java.util.ArrayList;
  13. import java.util.List;
  14. /**
  15. * 拦截器配置
  16. */
  17. @Configuration
  18. public class InterCepTerConfig implements WebMvcConfigurer {
  19. private TokenInterceptor tokenInterceptor;
  20. //构造方法
  21. public InterCepTerConfig(TokenInterceptor tokenInterceptor){
  22. this.tokenInterceptor = tokenInterceptor;
  23. }
  24. @Override
  25. public void addInterceptors(InterceptorRegistry registry){
  26. List<String> excludePath = new ArrayList<>();
  27. // excludePath.add("/user_register"); //注册
  28. // excludePath.add("/login"); //登录
  29. // excludePath.add("/logout"); //登出
  30. // excludePath.add("/static/**"); //静态资源
  31. // excludePath.add("/swagger-ui.html/**"); //静态资源
  32. // excludePath.add("/assets/**"); //静态资源
  33. registry.addInterceptor(tokenInterceptor)
  34. .addPathPatterns("/**")
  35. .excludePathPatterns(excludePath);
  36. WebMvcConfigurer.super.addInterceptors(registry);
  37. }
  38. /**
  39. * 跨域支持
  40. *
  41. * @param registry
  42. */
  43. @Override
  44. public void addCorsMappings(CorsRegistry registry) {
  45. registry.addMapping("/**")
  46. .allowedOrigins("*")
  47. .allowCredentials(true)
  48. .allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH", "OPTIONS", "HEAD")
  49. .maxAge(3600 * 24);
  50. }
  51. }
  52. package com.zkhx.filter;
  53. import com.alibaba.fastjson.JSONObject;
  54. import com.zkhx.uitls.JwtUtils;
  55. import io.jsonwebtoken.Claims;
  56. import io.jsonwebtoken.Jwts;
  57. import org.springframework.stereotype.Component;
  58. import org.springframework.web.servlet.HandlerInterceptor;
  59. import javax.servlet.http.HttpServletRequest;
  60. import javax.servlet.http.HttpServletResponse;
  61. import java.io.PrintWriter;
  62. import java.text.SimpleDateFormat;
  63. import java.util.Date;
  64. /**
  65. * @author qinKJ
  66. * @version 1.0
  67. * @date 2020.12.30 14:07
  68. * 防止直接访问
  69. */
  70. @Component
  71. public class TokenInterceptor implements HandlerInterceptor {
  72. @Override
  73. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception{
  74. if(request.getMethod().equals("OPTIONS")){
  75. response.setStatus(HttpServletResponse.SC_OK);
  76. return true;
  77. }
  78. response.setCharacterEncoding("utf-8");
  79. String token = request.getHeader("AuthToken");
  80. if(token != null){
  81. boolean result = JwtUtils.checkToken(token);
  82. if(result){
  83. return true;
  84. }
  85. }
  86. response.setCharacterEncoding("UTF-8");
  87. response.setContentType("application/json; charset=utf-8");
  88. PrintWriter out = null;
  89. try{
  90. JSONObject json = new JSONObject();
  91. json.put("success","false");
  92. json.put("msg","不能从这里访问哟");
  93. json.put("code","50000");
  94. response.getWriter().append(json.toJSONString());
  95. System.out.println("认证失败,未通过拦截器");
  96. // response.getWriter().write("50000");
  97. }catch (Exception e){
  98. e.printStackTrace();
  99. response.sendError(500);
  100. return false;
  101. }
  102. return false;
  103. }
  104. }

完毕,不通过网关访问接口:
在这里插入图片描述
登录服务获取到token,通过postman调试
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
替换token后再次访问
在这里插入图片描述
刷新成功

发表评论

表情:
评论列表 (有 0 条评论,240人围观)

还没有评论,来说两句吧...

相关阅读