分布式session解决方案 — — JWT(生成token)
JWT 跨域认证解决方案
1 介绍
- JWT(JSON Web Token)是目前最流行的跨域认证解决方案,是一种基于Token的认证授权机制,JWT本身也是Token,是一种规范化之后的JSON结构的Token。
- JWT自身包含了验证所需要的所有信息,因此,我们的服务器不需要存储Session信息(其他解决方案:hash、session共享),增加了系统的可用性和伸缩性,大大减轻了服务端的压力。
- JWT更符合RESTFul API的无状态原则
- JWT认证可以有效避免CSRF(跨站请求伪造攻击),因为JWT一般是存在在localStorage中,使用JWT进行身份验证的过程中不会涉及到Cookie
2 组成部分
JWT本质就是一组字符串,通过(.)切分成三个为Base64编码的部分:
- Header:描述JWT元数据,定义生成签名的算法及Token类型
- Payload:存放实际要传递的数据
- Signature(签名):服务器通过Payload、Header和一个密钥(Secret)使用Header里面指定的签名算法(默认是HMAC SHA256)
实例:用点分割,分为三部分
3 JWT工具类的编写(企业开发)
3.1 定义对应编码及盐值(加密时)
//定义对应的编码算法
static SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
//盐值,盐值随意,看公司要求【此处我采用UUID】
static String secretKey = "d8de020f63754a9fa746ea74b831afc3";
3.2 获取key
//获取key(指定算法和盐值的key对象)
private static Key generateKey(){
//将盐值转成字节
byte[] bytes = DatatypeConverter.parseBase64Binary(secretKey);
//根据算法和盐值生成对应的key值
Key key = new SecretKeySpec(bytes, signatureAlgorithm.getJcaName());
return key;
}
3.3 生成token(generatorToken)
/**
* 将我们的数据使用JWT的方式变成一个token xxx.yyy.zzz
* @param payLoad 负载(数据信息)
* @return
*/
public static String generatorToken(Map<String, String> payLoad){
ObjectMapper objectMapper = new ObjectMapper();
try{
//构建jwt生成器
JwtBuilder builder = Jwts.builder();
//将负载信息设置到jwt生成器中
JwtBuilder jwtBuilder = builder.setPayload(objectMapper.writeValueAsString(payLoad));
//根据签名算法和key值,生成新的jwtBuilder
JwtBuilder jwtBuilder1 = jwtBuilder.signWith(signatureAlgorithm, generateKey());
String token = jwtBuilder1.compact();
return token;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
3.4 获取token中的body信息
/**
* 根据指定的token, 返回对应的body信息
* @param token
* @return
*/
public static Claims phaseTokenGetBody(String token){
JwtParser jwtParser = Jwts.parser().setSigningKey(generateKey());
Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
Claims body = claimsJws.getBody();//主要存放的信息
return body;
}
3.5 获取token中的signature信息
/**
* 根据指定的token获取签名信息
* @param token
* @return
*/
public static String phaseTokenGetSignature(String token){
JwtParser jwtParser = Jwts.parser().setSigningKey(generateKey());
Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
String signature = claimsJws.getSignature();
return signature;
}
3.6 获取token中的头信息
/**
* 根据指定的token获取头信息
* @param token
* @return
*/
public static JwsHeader phaseTokenGetHeader(String token){
//获取解析器
JwtParser parser = Jwts.parser();
//设置签名key(盐值)
parser = parser.setSigningKey(generateKey());
//解析token
Jws<Claims> claimsJws = parser.parseClaimsJws(token);
JwsHeader header = claimsJws.getHeader();
return header;
}
3.7 测试
①在map中存入自己的数据,调用自定义API生成对应token
public static void main(String[] args) {
//随机获取盐值
// System.out.println(UUID.randomUUID().toString().replaceAll("-", ""));
Map<String, String> payLoad = new HashMap<>();
payLoad.put("name", "curry");
String s = generatorToken(payLoad);
//eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiY3VycnkifQ.Sf3GiF3p56nLzoAxEHLXcAckPmmPTtecj1_lGT9oV8s
System.out.println(s);
}
②在jwt官网https://jwt.io/中进行解析,也可以调用自己的API进行解析
调用自己API:
//调用自定义API获取结果
Claims claims = phaseTokenGetBody(s);
//{name=curry}
③如果所给token有误,则会报错
Exception in thread "main" io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
4 全部代码包含测试
package com.zi.api.commons.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.*;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.HashMap;
import java.util.Map;
/**
* 生成jwt工具类
*/
public class JJWTRootUtils {
//定义对应的编码算法
static SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
//盐值
static String secretKey = "d8de020f63754a9fa746ea74b831afc3";
//获取key(指定算法和盐值的key对象)
private static Key generateKey(){
//将盐值转成字节
byte[] bytes = DatatypeConverter.parseBase64Binary(secretKey);
//根据算法和盐值生成对应的key值
Key key = new SecretKeySpec(bytes, signatureAlgorithm.getJcaName());
return key;
}
/**
* 将我们的数据使用JWT的方式变成一个token xxx.yyy.zzz
* @param payLoad 负载(数据信息)
* @return
*/
public static String generatorToken(Map<String, String> payLoad){
ObjectMapper objectMapper = new ObjectMapper();
try{
//构建jwt生成器
JwtBuilder builder = Jwts.builder();
//将负载信息设置到jwt生成器中
JwtBuilder jwtBuilder = builder.setPayload(objectMapper.writeValueAsString(payLoad));
//根据签名算法和key值,生成新的jwtBuilder
JwtBuilder jwtBuilder1 = jwtBuilder.signWith(signatureAlgorithm, generateKey());
String token = jwtBuilder1.compact();
return token;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
/**
* 根据指定的token, 返回对应的body信息
* @param token
* @return
*/
public static Claims phaseTokenGetBody(String token){
JwtParser jwtParser = Jwts.parser().setSigningKey(generateKey());
Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
Claims body = claimsJws.getBody();//主要存放的信息
return body;
}
/**
* 根据指定的token获取签名信息
* @param token
* @return
*/
public static String phaseTokenGetSignature(String token){
JwtParser jwtParser = Jwts.parser().setSigningKey(generateKey());
Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
String signature = claimsJws.getSignature();
return signature;
}
/**
* 根据指定的token获取头信息
* @param token
* @return
*/
public static JwsHeader phaseTokenGetHeader(String token){
//获取解析器
JwtParser parser = Jwts.parser();
//设置签名key(盐值)
parser = parser.setSigningKey(generateKey());
//解析token
Jws<Claims> claimsJws = parser.parseClaimsJws(token);
JwsHeader header = claimsJws.getHeader();
return header;
}
public static void main(String[] args) {
//随机获取盐值
// System.out.println(UUID.randomUUID().toString().replaceAll("-", ""));
Map<String, String> payLoad = new HashMap<>();
payLoad.put("name", "curry");
String s = generatorToken(payLoad);
//eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiY3VycnkifQ.Sf3GiF3p56nLzoAxEHLXcAckPmmPTtecj1_lGT9oV8s
System.out.println(s);
//调用自定义API获取结果
Claims claims = phaseTokenGetBody(s);
//{name=curry}
System.out.println(claims);
}
}
还没有评论,来说两句吧...