上一篇文章讲解了JWT的基本简介,这一篇文章我就来实战一下。介绍一下在分布式单点登录中的使用方法:
首先来看一下Token实体类,
public class Token implements Serializable{
private static final long serialVersionUID = -5391652691006115018L;
/** 认证头 **/
private Head head;
/** 认证信息有效载荷 **/
private Playload playload;
/** 第一部分:base64head头 **/
private String base64Head;
/** 第二部分:base64playload荷载 **/
private String base64PlayLoad;
/** 第三部分:签证信息 **/
private String signature;
/** 最终token字符串 **/
private String tokenStr;
/**
* Token头
*
*
*/
public static class Head implements Serializable{
private static final long serialVersionUID = -6516084948347601103L;
/** token类型 **/
private String typ = "JWT";
/** token算法 默认:HMAC SHA256**/
private String alg = "HS256";
public String getTyp() {
return typ;
}
public void setTyp(String typ) {
this.typ = typ;
}
public String getAlg() {
return alg;
}
public void setAlg(String alg) {
this.alg = alg;
}
}
/**
* Token有效载荷
*
*
*/
public static class Playload implements Serializable {
private static final long serialVersionUID = 3981890375700111920L;
/** 该token签发者 **/
private String iss;
/** 该token的所有人,可以存放用户名 **/
private String sub;
/** 接收token的一方 **/
private String aud;
/** token的过期时间(时间戳),必须要大于签发时间;大于等于该时间需要刷新token **/
private long exp;
/** token生效的开始时间(时间戳),意味着在这个时间之前验证token是会失败的,默认生成token后立即生效 **/
private long nbf;
/** token的签发时间 时间戳**/
private long iat;
/** token的唯一身份标识,主要用来作为一次性token,从而回避重放攻击 **/
private String jti;
/** token验证宽限时间(时间戳) 超过宽限时间需要重新登录,
* 即该token的真正存活时间,宽限时间的加入是为了解决并发token刷新后新token失效问题
* **/
private long gra;
/** token类型: 后台登录用户,互联网用户,第三方机构 **/
private String typ;
public String getIss() {
return iss;
}
public void setIss(String iss) {
this.iss = iss;
}
public String getSub() {
return sub;
}
public void setSub(String sub) {
this.sub = sub;
}
public String getAud() {
return aud;
}
public void setAud(String aud) {
this.aud = aud;
}
public long getExp() {
return exp;
}
public void setExp(long exp) {
this.exp = exp;
}
public long getNbf() {
return nbf;
}
public void setNbf(long nbf) {
this.nbf = nbf;
}
public long getIat() {
return iat;
}
public void setIat(long iat) {
this.iat = iat;
}
public String getJti() {
return jti;
}
public void setJti(String jti) {
this.jti = jti;
}
public long getGra() {
return gra;
}
public void setGra(long gra) {
this.gra = gra;
}
public String getTyp() {
return typ;
}
public void setTyp(String typ) {
this.typ = typ;
}
}
public Head getHead() {
return head;
}
public void setHead(Head head) {
this.head = head;
}
public Playload getPlayload() {
return playload;
}
public void setPlayload(Playload playload) {
this.playload = playload;
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
public String getBase64Head() {
return base64Head;
}
public void setBase64Head(String base64Head) {
this.base64Head = base64Head;
}
public String getBase64PlayLoad() {
return base64PlayLoad;
}
public void setBase64PlayLoad(String base64PlayLoad) {
this.base64PlayLoad = base64PlayLoad;
}
public String getTokenStr() {
return tokenStr;
}
public void setTokenStr(String tokenStr) {
this.tokenStr = tokenStr;
}
}
可以看到实体类里面包含了head payload signature这三部分。
然后用户登录成功之后创建token的代码如下:
public static Token createToken(String secret,String tokenId,TokenType tokenType,String userName) {
try {
Token token = new Token();
//创建头
Token.Head head = new Token.Head();
head.setAlg("HS256");
head.setTyp("JWT");
//创建载荷
//签发时间
long iat = System.currentTimeMillis();
//过期时间 20 分钟后过期
long exp = iat + AuthConstants.TOKEN_EXP_TIME ;
//最后存活时间
long gra = iat + AuthConstants.TOKEN_GRA_TIME ;
Token.Playload playload = new Token.Playload();
playload.setAud("CLIENT"); //接收token的一方
playload.setIat(iat); //签发时间
playload.setExp(exp);
playload.setGra(gra);
playload.setIss("AUTH_CENTER");//签发者
playload.setJti(tokenId); //token唯一身份标识
playload.setNbf(iat);//生效时间,立即生效
playload.setSub(userName); //token的所属者,可以存放用户名
playload.setTyp(tokenType.toString().toUpperCase());
//创建token
String base64Head = Base64Util.encodeStr(JSONUtil.toJson(head) );
String base64Playload = Base64Util.encodeStr(JSONUtil.toJson(playload) );
String signature = HmacUtil.encryptHMACSHA256(base64Head+"."+base64Playload, secret); //token签名
String tokenStr = base64Head+"."+base64Playload+"."+signature; //token字符串
//组装token对象
token.setHead(head);
token.setPlayload(playload);
token.setBase64Head(base64Head);
token.setBase64PlayLoad(base64Playload);
token.setSignature(signature);
token.setTokenStr(tokenStr);
return token;
} catch (Exception e) {
e.printStackTrace();
logger.error("生成token失败:{}",e.getMessage());
}
return null;
}
创建成功之后,要把token放到响应头中,setHeader方法name参数要用Authorization,value值要使用
"Bearer "+token。
然后用户访问需要权限的接口都需要在请求头加上token,因为使用了Spring Cloud微服务架构,因此请求
会统一通过API网关访问,所以需要在网关处验证token的合法性,使用下面这个parseToken的方法:
/**
* 验证并解析token
* @param token token字符串
* @param secret token签名的盐(密钥)
* @return 成功返回token ,失败返回ull
*/
public static Token parseToken(String token,String secret) {
try {
//判断token是否是合法格式的token串
if(StringUtils.isEmpty(token)) {
throw new AuthException("token串为空!");
}
if(StringUtils.isEmpty(secret)) {
throw new AuthException("解析token时,token密钥为空!");
}
String[] tokens = token.split("\\.");
if(tokens==null || tokens.length!=3) {
throw new AuthException("非法格式的token串:"+token);
}
//token分解
String base64Head = tokens[0].trim(); //token头
String base64Playload = tokens[1].trim(); //token载荷
String signature = tokens[2].trim(); //token签名
//验证签名是否为合法的
String signData = base64Head+"."+base64Playload;
String signaturedStr = HmacUtil.encryptHMACSHA256(signData, secret.trim()); //token签名
if(!signature.equals(signaturedStr)) {
throw new AuthException("非法的token:解析token时,token验签失败!");
}
Token.Head head = JSONUtil.toBean(Base64Util.decodeStr(base64Head), Token.Head.class);
Token.Playload playLoad = JSONUtil.toBean(Base64Util.decodeStr(base64Playload), Token.Playload.class);
Token rs = new Token();
rs.setHead(head);
rs.setPlayload(playLoad);
rs.setSignature(signature);
return rs;
} catch (Exception e) {
e.printStackTrace();
logger.error("解析token失败:{}",e.getMessage());
return null;
}
}
使用JWT进行身份验证的基本方法的实例就到这里,没有接触过JWT的同学可以先看一下JWT
的简介:http://blog.youkuaiyun.com/a18716374124/article/details/78474955