SpringCloud利用网关拦截做Token验证(JWT方式)

时间:2024-11-15 20:51:30

关于JWT的内容,请看以下链接,主要看它的原理,以及缺点!

/memmsc/article/details/78122931

步骤1:前端传userName+password到后端,后端为springcloud架构,经过网关的拦截器拦截请求,拦截器在项目启动的时候@Component进行加载。

步骤2:如果是第一次登陆,放行,进入JWT的加密生成Token阶段(还可以写入登陆用户的其他信息放在JWTmap中,之后可以利用Token来获取该用户信息),加密token需要一个随机数作为加密字段,将token的失效时间设置为一天,并且放到reids里面,设置该redis里面的token过期时间为30分钟,最后将Token返回给前端。

步骤3:以后任何的请求都带Token到后端去请求。

步骤4:拦截到非登陆请求,进行解密,鉴权,如果鉴权通过,更新redis里面token字段的失效时间,如果还有5分钟失效,再设置还有30分钟,目的就是让密码的过期时间变的活跃。

大致就是以上的过程,核心代码主要在网关拦截器解密鉴权和登陆接口的加密两部分

0,controller层的将得到的token做保存redis和设置过期时间的操作


 
 
  1. compactJws = (username, password, userBean);
  2. //将token存在redis里
  3. (). set( "token", compactJws);
  4. //设置redis里面的数据失效时间为半小时
  5. ( "token", 1800, TimeUnit. SECONDS);

1,登陆接口的加密:


 
 
  1. package ;
  2. import ;
  3. import ;
  4. import ;
  5. import ;
  6. import ;
  7. import ;
  8. import ;
  9. import .Base64;
  10. import ;
  11. import ;
  12. /**
  13. * 用户身份验证Service
  14. */
  15. @ Service(value = "authService")
  16. public class AuthServiceImpl implements AuthService {
  17. @ Override
  18. public String generateJwt( String userName, String userPassword, UserBean userBean) {
  19. // Base64编码后的secretKey
  20. byte[] secretKey = Base64.getEncoder().encode( CommonConstants. SECURITY_KEY.getBytes());
  21. // 设置失效时间
  22. DateTime expirationDate = new DateTime().plusDays( 1);
  23. //DateTime expirationDate = new DateTime().plusMinutes(30);
  24. // Claims是需要保存到token中的信息,可以自定义,需要存什么就放什么,会保存到token的payload中
  25. Map< String, Object> claims = new HashMap<>();
  26. // 用户角色
  27. ( "role", "user");
  28. // 用户名
  29. ( "userName", userName);
  30. ( CommonConstants. USER_ID, ());
  31. ( "uuid", UUID.randomUUID(). toString());
  32. String compactJws = Jwts.builder()
  33. // 设置subject,一般是用户的唯一标识,比如用户对象的ID,用户名等,目前设置的是userCode
  34. .setSubject(userName)
  35. // 设置失效时间
  36. .setExpiration(())
  37. .addClaims(claims)
  38. // 加密算法是HS512,加密解密统一就可以
  39. .signWith( SignatureAlgorithm. HS512, secretKey)
  40. .compact();
  41. return compactJws;
  42. }
  43. }

以上常量类和pojo此处省略。。。。

2,网关拦截器解密鉴权:


 
 
  1. package ;
  2. import ;
  3. import ;
  4. import ;
  5. import ;
  6. import ;
  7. import ;
  8. import ;
  9. import .*;
  10. import ;
  11. import ;
  12. import ;
  13. import ;
  14. import ;
  15. import ;
  16. import .Base64;
  17. @Component
  18. public class SecurityFilter extends ZuulFilter {
  19. @Override
  20. public String filterType() {
  21. return FilterConstants.PRE_TYPE;
  22. }
  23. @Override
  24. public int filterOrder() {
  25. return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
  26. }
  27. @Override
  28. public boolean shouldFilter() {
  29. RequestContext ctx = ();
  30. HttpServletRequest request = ();
  31. if (().toString().contains( "loginInfo") || ().toString().contains( "info")) {
  32. return false;
  33. }
  34. // TODO
  35. return true;
  36. }
  37. @Override
  38. public Object run() {
  39. RequestContext ctx = ();
  40. HttpServletRequest request = ();
  41. final String authorizationHeader = ();
  42. if (().equals(())) {
  43. return null;
  44. } else {
  45. if ((authorizationHeader) || !()) {
  46. // Missing or invalid Authorization header
  47. ErrorResponseMap errorResponseMap = ( null, "Missing or invalid Authorization header!",
  48. ErrorCode.INVALID_AUTHORIZATION_HEADER, request, null);
  49. denyAccess(ctx,errorResponseMap);
  50. return (errorResponseMap);
  51. }
  52. final String token = ( 7);
  53. try {
  54. byte[] secretKey = ().encode(CommonConstants.SECURITY_KEY.getBytes());
  55. Claims claims = ().setSigningKey(secretKey).parseClaimsJws(token).getBody();
  56. if (claims != null) {
  57. //获取redis里面数据的存活时间
  58. Long expirationDate = ( "token",);
  59. //如果还剩余5分钟,重置redis里面数据的存活时间
  60. if(expirationDate > 300){
  61. ( "token", 1800,);
  62. } else {
  63. ErrorResponseMap errorResponseMap = new ErrorResponseMap();
  64. Error error = new Error( null, "Token expired!", "", 1003, "");
  65. ( false);
  66. ( null);
  67. (error);
  68. denyAccess(ctx,errorResponseMap);
  69. return (errorResponseMap);
  70. }
  71. String userName = (String) claims. get(CommonConstants.USER_CODE);
  72. Integer userId = (Integer) claims. get(CommonConstants.USER_ID);
  73. (CommonConstants.USER_CODE, userName);
  74. (CommonConstants.USER_ID, (userId));
  75. }
  76. } catch (MalformedJwtException ex) {
  77. ErrorResponseMap errorResponseMap = ( null, "Invalid token!",
  78. ErrorCode.INVALID_AUTHORIZATION_HEADER, request, ex);
  79. denyAccess(ctx,errorResponseMap);
  80. return (errorResponseMap);
  81. } catch (SignatureException ex) {
  82. ErrorResponseMap errorResponseMap = ( null, "Token Signature error!",
  83. ErrorCode.SIGNATURE_EXCEPTION, request, ex);
  84. denyAccess(ctx,errorResponseMap);
  85. return (errorResponseMap);
  86. } catch (ExpiredJwtException ex) {
  87. ErrorResponseMap errorResponseMap = ( null, "Token expired!",
  88. ErrorCode.EXPIRED_JWT_EXCEPTION, request, ex);
  89. denyAccess(ctx,errorResponseMap);
  90. return (errorResponseMap);
  91. }
  92. }
  93. return null;
  94. }
  95. private void denyAccess(RequestContext ctx, ErrorResponseMap authResult) {
  96. String result = (authResult);
  97. ( false);
  98. ( 401);
  99. try {
  100. ().getWriter().write(result);
  101. } catch (Exception e){}
  102. }
  103. }

以上代码是核心代码,下面是自己项目中涉及到的异常包装类,以及util类,可以不管下面的,直接去封装

 

以上涉及到的类:

(1)ErrorResponseMap


 
 
  1. package com .movitech .commons .dto;
  2. import com .fasterxml .jackson .annotation .JsonProperty;
  3. import com .movitech .commons .exception .Error;
  4. import lombok .Getter;
  5. import lombok .Setter;
  6. @ Getter
  7. @Setter
  8. public class ErrorResponseMap extends ResponseMap {
  9. @ JsonProperty( value = "error")
  10. private Error error;
  11. @ JsonProperty( value = "stackTrace")
  12. private String stackTrace;
  13. }

(1.1)Error


 
 
  1. package ;
  2. import ;
  3. import ;
  4. import ;
  5. import ;
  6. @Getter
  7. @Setter
  8. @NoArgsConstructor
  9. @AllArgsConstructor
  10. public class Error {
  11. // 标准的 Http status code
  12. private Integer httpStatusCode;
  13. // 自定义的错误说明
  14. private String errorMsg;
  15. // 异常信息
  16. private String exceptionMsg;
  17. // 自定义的错误代码
  18. private Integer errorCode;
  19. // 异常的类名
  20. private String exceptionClassName;
  21. }

(2)ErrorCode


 
 
  1. package ;
  2. /**
  3. * 自定义的错误代码的枚举
  4. */
  5. public enum ErrorCode {
  6. // Token 签名错误
  7. SIGNATURE_EXCEPTION( 1000),
  8. // Token 过期
  9. EXPIRED_JWT_EXCEPTION( 1001),
  10. // 无效的Authorization header
  11. INVALID_AUTHORIZATION_HEADER( 1002);
  12. private Integer errorCode;
  13. ErrorCode(Integer errorCode) {
  14. this.errorCode = errorCode;
  15. }
  16. @Override
  17. public String toString() {
  18. return ();
  19. }
  20. public Integer value() {
  21. return errorCode;
  22. }
  23. }

(3)JsonUtil


 
 
  1. package ;
  2. import ;
  3. import .*;
  4. import .Jackson2ObjectMapperBuilder;
  5. import ;
  6. import ;
  7. import ;
  8. /**
  9. * Json序列化和反序列化
  10. */
  11. @Component
  12. public class JsonUtil
  13. {
  14. public static ObjectMapper mapper;
  15. /* static {
  16. dao = new ObjectMapper();
  17. (SerializationFeature.WRAP_ROOT_VALUE,true);
  18. (DeserializationFeature.UNWRAP_ROOT_VALUE, true);
  19. }*/
  20. public JsonUtil(Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder) {
  21. mapper = ();
  22. }
  23. public static String serializeToString(Object object) {
  24. return serializeToString( object, false);
  25. }
  26. public static String serializeToString(Object object, Boolean rootValueState) {
  27. SerializationConfig serializationConfig = ();
  28. (SerializationFeature.WRAP_ROOT_VALUE,rootValueState);
  29. if ( object != null) {
  30. try {
  31. return ( object);
  32. } catch (JsonProcessingException e) {
  33. ();
  34. } finally {
  35. (serializationConfig);
  36. }
  37. }
  38. return "";
  39. }
  40. public static byte[] serializeToBytes(Object object) {
  41. if ( object != null) {
  42. try {
  43. return ( object);
  44. } catch (JsonProcessingException e) {
  45. ();
  46. }
  47. }
  48. return null;
  49. }
  50. /**
  51. * 反序列化Json数据
  52. * @param jsonData Json数据字符串
  53. * @param valueType 反序列化的类型
  54. * @param rootValueState 是否解析Json root name
  55. * @param <T>
  56. * @return 反序列化后的POJO
  57. */
  58. public static <T> T deserialize(String jsonData,Class<T> valueType, Boolean rootValueState) {
  59. if ((jsonData) || rootValueState == null) {
  60. return null;
  61. }
  62. DeserializationConfig deserializationConfig = ();
  63. (DeserializationFeature.UNWRAP_ROOT_VALUE,rootValueState);
  64. try {
  65. return (jsonData, valueType);
  66. } catch (IOException e) {
  67. ();
  68. } finally {
  69. (deserializationConfig);
  70. }
  71. return null;
  72. }
  73. /**
  74. * 反序列化Json数据,默认解析Json root name
  75. * @param jsonData Json数据字符串
  76. * @param valueType 反序列化的类型
  77. * @param <T>
  78. * @return 反序列化后的POJO
  79. */
  80. public static <T> T deserialize(String jsonData,Class<T> valueType) {
  81. return deserialize(jsonData, valueType, true);
  82. }
  83. public static JavaType getCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
  84. return ().constructParametricType(collectionClass, elementClasses);
  85. }
  86. /**
  87. * 用Json数据中的key获取对应的value
  88. * @param jsonString json数据字符串
  89. * @param field 需要取值的字段
  90. * @param rootValueState 是否解析Json root name
  91. * @return 字段对应的值
  92. */
  93. public static String getValue(String jsonString,String field, Boolean rootValueState) {
  94. JsonNode node = getJsonNode(jsonString,field,rootValueState);
  95. return node == null ? "" : ();
  96. }
  97. /**
  98. * 用Json数据中的key获取对应的value, 默认解析Json root name
  99. * @param jsonString json数据字符串
  100. * @param field 需要取值的字段
  101. * @return 字段对应的值
  102. */
  103. public static String getValue(String jsonString,String field) {
  104. return getValue(jsonString,field, true);
  105. }
  106. /**
  107. * 用Json数据中的key获取对应的value
  108. * @param jsonString json数据字符串
  109. * @param field 需要取值的字段
  110. * @param rootValueState 是否解析Json root name
  111. * @return 字段对应的值
  112. */
  113. public static JsonNode getJsonNode(String jsonString, String field, Boolean rootValueState) {
  114. if ((jsonString) || (field) || rootValueState == null) {
  115. return null;
  116. }
  117. // 准备工作 传入vo请参照第一篇里面的实体。此处不再重新贴上代码 浪费大家时间
  118. JsonNode node = null; // 这里的JsonNode和XML里面的Node很像
  119. // 默认的反序列化配置
  120. DeserializationConfig deserializationConfig = ();
  121. (DeserializationFeature.UNWRAP_ROOT_VALUE,rootValueState);
  122. try {
  123. node = (jsonString);
  124. } catch (IOException e) {
  125. ();
  126. return null;
  127. } finally {
  128. (deserializationConfig);
  129. }
  130. return node. get(field) == null ? null : node. get(field);
  131. }
  132. }

(4)ResponseUtil


 
 
  1. package ;
  2. import ;
  3. import ;
  4. import ;
  5. import ;
  6. import ;
  7. import ;
  8. public class ResponseUtil {
  9. public static ResponseEntity createResponseEntity(String errorMsg, ErrorCode errorCode, HttpServletRequest request, Throwable ex) {
  10. HttpStatus status = getStatus(request);
  11. ErrorResponseMap errorResponseMap = createErrorResponse(status, errorMsg, errorCode, request, ex);
  12. return new ResponseEntity<>(errorResponseMap, status);
  13. }
  14. public static ErrorResponseMap createErrorResponse(HttpStatus status, String errorMsg, ErrorCode errorCode, HttpServletRequest request, Throwable ex) {
  15. if (status == null) {
  16. status = getStatus(request);
  17. }
  18. ErrorResponseMap errorResponseMap = new ErrorResponseMap();
  19. Error error = new Error((), errorMsg, ex == null ? "" : (),
  20. errorCode == null ? HttpStatus.INTERNAL_SERVER_ERROR.value() : (), ex == null ? "" : ().getCanonicalName());
  21. ( false);
  22. (());
  23. (error);
  24. // String stackTrace = ((), "hahaha");
  25. // (stackTrace);
  26. return errorResponseMap;
  27. }
  28. public static HttpStatus getStatus(HttpServletRequest request) {
  29. Integer statusCode = (Integer) ( ".status_code");
  30. if (statusCode == null) {
  31. return HttpStatus.INTERNAL_SERVER_ERROR;
  32. }
  33. return (statusCode);
  34. }
  35. }

 

文章转载自:/qq_34707991/article/details/82898187