Spring Cloud Gateway 实现Token校验
Posted 狂乱的贵公子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Cloud Gateway 实现Token校验相关的知识,希望对你有一定的参考价值。
在我看来,在某些场景下,网关就像是一个公共方法,把项目中的都要用到的一些功能提出来,抽象成一个服务。比如,我们可以在业务网关上做日志收集、Token校验等等,当然这么理解很狭隘,因为网关的能力远不止如此,但是不妨碍我们更好地理解它。下面的例子演示了,如何在网关校验Token,并提取用户信息放到Header中传给下游业务系统。
1. 生成Token
用户登录成功以后,生成token,此后的所有请求都带着token。网关负责校验token,并将用户信息放入请求Header,以便下游系统可以方便的获取用户信息。
为了方便演示,本例中涉及三个工程
公共项目:cjs-commons-jwt
认证服务:cjs-auth-service
网关服务:cjs-gateway-example
1.1. Token生成与校验工具类
因为生成token在认证服务中,token校验在网关服务中,因此,我把这一部分写在了公共项目cjs-commons-jwt中
pom.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2
3 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 <modelVersion>4.0.0</modelVersion>
6
7 <groupId>com.cjs.example</groupId>
8 <artifactId>cjs-commons-jwt</artifactId>
9 <version>1.0-SNAPSHOT</version>
10
11 <properties>
12 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13 <maven.compiler.source>1.8</maven.compiler.source>
14 <maven.compiler.target>1.8</maven.compiler.target>
15 </properties>
16
17 <dependencies>
18 <dependency>
19 <groupId>com.auth0</groupId>
20 <artifactId>java-jwt</artifactId>
21 <version>3.10.0</version>
22 </dependency>
23 <dependency>
24 <groupId>org.apache.commons</groupId>
25 <artifactId>commons-lang3</artifactId>
26 <version>3.9</version>
27 </dependency>
28 <dependency>
29 <groupId>com.alibaba</groupId>
30 <artifactId>fastjson</artifactId>
31 <version>1.2.66</version>
32 </dependency>
33 </dependencies>
34
35 </project>
JWTUtil.java
1 package com.cjs.example.utils;
2
3 import com.auth0.jwt.JWT;
4 import com.auth0.jwt.JWTVerifier;
5 import com.auth0.jwt.algorithms.Algorithm;
6 import com.auth0.jwt.exceptions.JWTDecodeException;
7 import com.auth0.jwt.exceptions.SignatureVerificationException;
8 import com.auth0.jwt.exceptions.TokenExpiredException;
9 import com.auth0.jwt.interfaces.DecodedJWT;
10 import com.cjs.example.enums.ResponseCodeEnum;
11 import com.cjs.example.exception.TokenAuthenticationException;
12
13 import java.util.Date;
14
15 /**
16 * @author ChengJianSheng
17 * @date 2020-03-08
18 */
19 public class JWTUtil {
20
21 public static final long TOKEN_EXPIRE_TIME = 7200 * 1000;
22 private static final String ISSUER = "cheng";
23
24 /**
25 * 生成Token
26 * @param username 用户标识(不一定是用户名,有可能是用户ID或者手机号什么的)
27 * @param secretKey
28 * @return
29 */
30 public static String generateToken(String username, String secretKey) {
31 Algorithm algorithm = Algorithm.HMAC256(secretKey);
32 Date now = new Date();
33 Date expireTime = new Date(now.getTime() + TOKEN_EXPIRE_TIME);
34
35 String token = JWT.create()
36 .withIssuer(ISSUER)
37 .withIssuedAt(now)
38 .withExpiresAt(expireTime)
39 .withClaim("username", username)
40 .sign(algorithm);
41
42 return token;
43 }
44
45 /**
46 * 校验Token
47 * @param token
48 * @param secretKey
49 * @return
50 */
51 public static void verifyToken(String token, String secretKey) {
52 try {
53 Algorithm algorithm = Algorithm.HMAC256(secretKey);
54 JWTVerifier jwtVerifier = JWT.require(algorithm).withIssuer(ISSUER).build();
55 jwtVerifier.verify(token);
56 } catch (JWTDecodeException jwtDecodeException) {
57 throw new TokenAuthenticationException(ResponseCodeEnum.TOKEN_INVALID.getCode(), ResponseCodeEnum.TOKEN_INVALID.getMessage());
58 } catch (SignatureVerificationException signatureVerificationException) {
59 throw new TokenAuthenticationException(ResponseCodeEnum.TOKEN_SIGNATURE_INVALID.getCode(), ResponseCodeEnum.TOKEN_SIGNATURE_INVALID.getMessage());
60 } catch (TokenExpiredException tokenExpiredException) {
61 throw new TokenAuthenticationException(ResponseCodeEnum.TOKEN_EXPIRED.getCode(), ResponseCodeEnum.TOKEN_INVALID.getMessage());
62 } catch (Exception ex) {
63 throw new TokenAuthenticationException(ResponseCodeEnum.UNKNOWN_ERROR.getCode(), ResponseCodeEnum.UNKNOWN_ERROR.getMessage());
64 }
65 }
66
67 /**
68 * 从Token中提取用户信息
69 * @param token
70 * @return
71 */
72 public static String getUserInfo(String token) {
73 DecodedJWT decodedJWT = JWT.decode(token);
74 String username = decodedJWT.getClaim("username").asString();
75 return username;
76 }
77
78 }
ResponseCodeEnum.java
1 package com.cjs.example.enums;
2
3 /**
4 * @author ChengJianSheng
5 * @date 2020-03-08
6 */
7 public enum ResponseCodeEnum {
8
9 SUCCESS(0, "成功"),
10 FAIL(-1, "失败"),
11 LOGIN_ERROR(1000, "用户名或密码错误"),
12 UNKNOWN_ERROR(2000, "未知错误"),
13 PARAMETER_ILLEGAL(2001, "参数不合法"),
14 TOKEN_INVALID(2002, "无效的Token"),
15 TOKEN_SIGNATURE_INVALID(2003, "无效的签名"),
16 TOKEN_EXPIRED(2004, "token已过期"),
17 TOKEN_MISSION(2005, "token缺失"),
18 REFRESH_TOKEN_INVALID(2006, "刷新Token无效");
19
20
21 private int code;
22
23 private String message;
24
25 ResponseCodeEnum(int code, String message) {
26 this.code = code;
27 this.message = message;
28 }
29
30 public int getCode() {
31 return code;
32 }
33
34 public String getMessage() {
35 return message;
36 }
37
38 }
ResponseResult.java
1 package com.cjs.example;
2
3 import com.cjs.example.enums.ResponseCodeEnum;
4
5 /**
6 * @author ChengJianSheng
7 * @date 2020-03-08
8 */
9 public class ResponseResult<T> {
10
11 private int code = 0;
12
13 private String msg;
14
15 private T data;
16
17 public ResponseResult(int code, String msg) {
18 this.code = code;
19 this.msg = msg;
20 }
21
22 public ResponseResult(int code, String msg, T data) {
23 this.code = code;
24 this.msg = msg;
25 this.data = data;
26 }
27
28 public static ResponseResult success() {
29 return new ResponseResult(ResponseCodeEnum.SUCCESS.getCode(), ResponseCodeEnum.SUCCESS.getMessage());
30 }
31
32 public static <T> ResponseResult<T> success(T data) {
33 return new ResponseResult(ResponseCodeEnum.SUCCESS.getCode(), ResponseCodeEnum.SUCCESS.getMessage(), data);
34 }
35
36 public static ResponseResult error(int code, String msg) {
37 return new ResponseResult(code, msg);
38 }
39
40 public static <T> ResponseResult<T> error(int code, String msg, T data) {
41 return new ResponseResult(code, msg, data);
42 }
43
44 public boolean isSuccess() {
45 return code == 0;
46 }
47
48 public int getCode() {
49 return code;
50 }
51
52 public void setCode(int code) {
53 this.code = code;
54 }
55
56 public String getMsg() {
57 return msg;
58 }
59
60 public void setMsg(String msg) {
61 this.msg 最全面的改造Zuul网关为Spring Cloud Gateway(包含Zuul核心实现和Spring Cloud Gateway核心实现)
Spring Cloud Gateway:retry 与 fallback