在我看来,在某些场景下,网关就像是一个公共方法,把项目中的都要用到的一些功能提出来,抽象成一个服务。比如,我们可以在业务网关上做日志收集、Token校验等等,当然这么理解很狭隘,因为网关的能力远不止如此,但是不妨碍我们更好地理解它。下面的例子演示了,如何在网关校验Token,并提取用户信息放到Header中传给下游业务系统。
1. 生成Token
用户登录成功以后,生成token,此后的所有请求都带着token。网关负责校验token,并将用户信息放入请求Header,以便下游系统可以方便的获取用户信息。
为了方便演示,本例中涉及三个工程
公共项目:commons-jwt
认证服务:auth-service
网关服务:gateway-service
1.1. Token生成与校验工具类
因为生成token在认证服务中,token校验在网关服务中,因此,我把这一部分写在了公共项目commons-jwt中
pom.xml
<dependencies>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.10.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.66</version>
</dependency>
</dependencies>
JWTUtil.java
public class JWTUtil {
private static final String USER_INFO_KEY = "username";
/**
* 生成Token
* @param issuser 签发者
* @param username 用户标识(唯一)
* @param secretKey 签名算法以及密匙
* @param tokenExpireTime 过期时间
* @return
*/
public static String generateToken(String issuser, String username, String secretKey, long tokenExpireTime) {
Algorithm algorithm = Algorithm.HMAC256(secretKey);
Date now = new Date();
Date expireTime = new Date(now.getTime() + tokenExpireTime);
String token = JWT.create()
.withIssuer(issuser)
.withIssuedAt(now)
.withExpiresAt(expireTime)
.withClaim(USER_INFO_KEY, username)
.sign(algorithm);
return token;
}
/**
* 校验Token
* @param issuser 签发者
* @param token 访问秘钥
* @param secretKey 签名算法以及密匙
* @return
*/
public static void verifyToken(String issuser, String token, String secretKey) {
try {
Algorithm algorithm = Algorithm.HMAC256(secretKey);
JWTVerifier jwtVerifier = JWT.require(algorithm).withIssuer(issuser).build();
jwtVerifier.verify(token);
} catch (JWTDecodeException jwtDecodeException) {
throw new TokenAuthenticationException(ResponseCodeEnum.TOKEN_INVALID.getCode(), ResponseCodeEnum.TOKEN_INVALID.getMessage());
} catch (SignatureVerificationException signatureVerificationException) {
throw new TokenAuthenticationException(ResponseCodeEnum.TOKEN_SIGNATURE_INVALID.getCode(), ResponseCodeEnum.TOKEN_SIGNATURE_INVALID.getMessage());
} catch (TokenExpiredException tokenExpiredException) {
throw new TokenAuthenticationException(ResponseCodeEnum.TOKEN_EXPIRED.getCode(), ResponseCodeEnum.TOKEN_INVALID.getMessage());
} catch (Exception ex) {
throw new TokenAuthenticationException(ResponseCodeEnum.UNKNOWN_ERROR.getCode(), ResponseCodeEnum.UNKNOWN_ERROR.getMessage()