JWT学习(二):JWT在分布式SSO中的应用实例

来源:互联网 发布:2017苹果春季发布会mac 编辑:程序博客网 时间:2024/06/14 21:26


上一篇文章讲解了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());//创建tokenString 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.csdn.net/a18716374124/article/details/78474955

原创粉丝点击