springCloud中由网关对请求统一进行分发和过滤。
什么是JWT
JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案,是一种紧凑且自包含的,用于在多方传递JSON对象的技术。在单点登录和分布式系统和多有使用
JWT包含三个部分,head,payload,签名,用.分隔开来
JWT头部分是一个描述JWT元数据的JSON对象,通常如下所示。
{
"alg": "HS256",
"typ": "JWT"
}
在上面的代码中,
alg属性表示签名使用的算法,默认为HMAC SHA256(写为HS256);
typ属性表示令牌的类型,JWT令牌统一写为JWT。
有效载荷
jwt中唯一可以不传任何数据的部分,
最后,使用Base64 URL算法将上述JSON对象转换为字符串保存。是JWT的主体内容部分,也是一个JSON对象,包含需要传递的数据
Signature
要创建签名部分,必须采用编码的Header+编码的Payload+秘钥,使用Header中指定的算法,并对其进行签名
例如如要使用HMAC SHA256算法,将按以下方式创建签名:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
最后得到的数据和head,payload用.进行组合,即得到jwt串
解决跨域请求问题
@Bean
public WebFilter corsFilter() {
return (ServerWebExchange ctx, WebFilterChain chain) -> {
ServerHttpRequest request = ctx.getRequest();
if (CorsUtils.isCorsRequest(request)) {
ServerHttpResponse response = ctx.getResponse();
HttpHeaders headers = response.getHeaders();
指定允许其他域名访问
headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
//允许的请求类型,GET,POST
headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
headers.add("Access-Control-Max-Age", MAX_AGE);
///允许的请求头字段
headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
headers.add("Access-Control-Expose-Headers", ALLOWED_Expose);
headers.add("Access-Control-Allow-Credentials", "true");
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
}
return chain.filter(ctx);
};
}
穿插了一个小知识,接下来介绍JAVA实现JWT加密认证
有效载荷中包含claims,
claims是关于实体(常用的是用户信息)和其他数据的声明,
claims有三种类型: registered, public, and private claims
接下来是Jwt机制的代码实现
定义一个字符用于创造秘钥
private static final String aesKey="xtasz";
根据提供的信息创建jwt加密串
public static String BuidJwtString(String userId,String userName){
//签名算法,选择SHA-256
SignatureAlgorithm signatureAlgorithm =SignatureAlgorithm.HS256;//这个类在io.jsonwebtoken.*; 别导错了
//添加构成JWT的参数,入参前面有介绍
Map<String, Object> headMap = new HashMap<>();
headMap.put("alg", SignatureAlgorithm.HS256.getValue());//就是HS256
headMap.put("typ", "JWT");
//将常量字符串使用base64解码成字节数组
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(aesKey);
//使用HmacSHA256签名算法生成一个HS256的签名秘钥Key
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
//创建builder
JwtBuilder jwtBuilder= Jwts.builder().setHeader(headMap).claim("userId",userId)
.claim("userName",userName)
//指定签名的算法和秘钥
.signWith(signatureAlgorithm,signingKey);
//如果需要设置过期时间
long nowTimeMills=System.currentTimeMillis();//获取当前时间
long expiretime=nowTimeMills+10000;//10000毫秒后过期
Date date = new Date(expiretime);
jwtBuilder.setExpiration(date);
//返回创建好的jwt字符串
return jwtBuilder.compact();
}
解密jwt字符串(jwt过期时会抛出异常)
//解析jwt,返回Claims,可根据key获取载荷信息
public static Claims parseJwt(String jwtString){
Claims claims = null;//获取有效载荷中数据
if(StringUtils.isNotEmpty(jwtString)){
claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(aesKey))
.parseClaimsJws(jwtString).getBody();
}
return claims;
}
我们可以写个测试方法
public static void main(String[] args) {
String userName ="lee";
String userId ="009";
String jwdToken=JwtUtil.BuidJwtString(userName,userId);
System.out.println(jwdToken);
Claims claims=JwtUtil.parseJwt(jwdToken);
System.out.println(claims.get("userName"));
}
亲测可用
pom jar包地址
<!-- JWT相关 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>