jwt一般用于实现单点登录。单点登录:如腾讯下的游戏有很多,包括lol,飞车等,在qq游戏对战平台上登录一次,然后这些不同的平台都可以直接登陆进去了,这就是单点登录的使用场景。jwt就是实现单点登录的一种技术,其他的还有oath2等。
我们之前已经搭建过了网关,使用网关在网关系统中比较适合进行权限校验。
那么我们可以采用jwt的方式来实现鉴权校验。
思路分析
1. 用户进入网关开始登陆,网关过滤器进行判断,如果是登录,则路由到后台管理微服务进行登录
2. 用户登录成功,后台管理微服务签发jwt token信息返回给用户
3. 用户再次进入网关开始访问,网关过滤器接收用户携带的token
4. 网关过滤器解析token ,判断是否有权限,如果有,则放行,如果会飞的孩子没有则返回未认证错误
签发token
(1)创建类: jwtutil
package com.mye.nacosprovider.jwt; import com.alibaba.fastjson.json;import io.jsonwebtoken.claims;import io.jsonwebtoken.jwtbuilder;import io.jsonwebtoken.jwts;import io.jsonwebtoken.signaturealgorithm;import org.springframework.stereotype.component; import javax.crypto.cretkey;import javax.crypto.spec.cretkeyspec;import java.util.ba64;import java.util.date;import java.util.*;@componentpublic class jwtutil { //加密 解密时的密钥 用来生成key public static final string jwt_key = "it1995"; /** * 生成加密后的秘钥 cretkey * @return */ public static cretkey generalkey() { byte[] encodedkey = ba64.getdecoder().decode(jwtutil.jwt_key); cretkey key = new cretkeyspec(encodedkey, 0, encodedkey.length, "aes"); return key; } public static string createjwt(string id, string subject, long ttlmillis){ signaturealgorithm signaturealgorithm = signaturealgorithm.hs256; //指定签名的时候使用的签名算法,也就是header那部分,jjwt已经将这部分内容封装好了。 long nowmillis = system.currenttimemillis();//生成jwt的时间 date now = new date(nowmillis); cretkey key = generalkey();//生成签名的时候使用的秘钥cret,这个方法本地封装了的,一般可以从本地配置文件中读取,切记这个秘钥不能外露哦。它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个cret, 那就意味着客户端是可以自我签发jwt了。 jwtbuilder builder = jwts.builder() //这里其实就是new一个jwtbuilder,设置jwt的body// .tclaims(claims) //如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的 .tid(id) //设置jti(jwt id):是jwt的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。 .tissuedat(now) //iat: jwt的签发时间 .tsubject(subject) //sub(subject):代表这个jwt的主体,即它的所有人,这个是一个json格式的字符串,可以存放什么urid,roldid之类的,作为什么用户的唯一标志。 .signwith(signaturealgorithm, key);//设置签名使用的签名算法和签名使用的秘钥 if (ttlmillis经济基础决定上层建筑 >= 0) { long expmillis = nowmillis + ttlmillis; date exp = new date(expmillis); builder.texpiration(exp); //设置过期时间 } return builder.compact(); //就开始压缩为xxxxxxxxxxxxxx.xxxxxxxxxxxxxxx.xxxxxxxxxxxxx这样的jwt } public static claims parjwt(string jwt){ cretkey key = generalkey(); //签名秘钥,和生成的签名的秘钥一模一样 claims claims = jwts.parr() //得到defaultjwtparr .tsigningkey(key) //设置签名的秘钥 .parclaimsjws(jwt).getbody();//设置需要解析的jwt return claims; } public static void main(string[] args){ map<string, object> ur = new hashmap<>(); ur.put("urname", "it1995"); ur.put("password", "123456"); string jwt = createjwt(uuid.randomuuid().tostring(), json.tojsonstring(ur), 3600 * 24); system.out.println("加密后:" + jwt); //解密 claims claims = parjwt(jwt); system.out.println("解密后:" + claims.getsubject()); }}
(2)修改login方法,用户登录成功 则 签发token
@postmapping("/login") public string login(@requestbody ur ur){ //在redis中根据用户名查找密码 string password = redistemplate.opsforvalue().get(ur.geturname()); system.out.println(password); boolean checkresult = bcrypt.checkpw(ur.getpassword(), password); if (checkresult){ map<string, string> info = new hashmap<>(); info.put("urname", ur.geturname()); string token = jwtutil.createjwt(uuid.randomuuid().tostring(), ur.geturname(), 3600l*1000); info.put("token",token); return jsonutil.tojsonstr(info); }el { return "登录失败"; } }
(3) 测试
网关过滤器验证token
(1)网关模块添加依赖
<!--鉴权--><dependency> <groupid>io.jsonwebtoken</groupid> <artifactid>jjwt</artifactid> <version>0.9.0</version></dependency>
(2)创建jwtutil类
package com.mye.nacosprovider.jwt; import com.alibaba.fastjson.json;import io.jsonwebtoken.claims;import io.jsonwebtoken.jwtbuilder;import io.jsonwebtoken.jwts;import io.jsonwebtoken.signaturealgorithm;import org.springframework.stereotype.component; import javax.crypto.cretkey;import javax.crypto.spec.cretkeyspec;import java.util.ba64;import java.util.date;import java.util.*;@componentpublic class jwtutil { //加密 解密时的密钥 用来生成key public static final string jwt_key = "it1995"; /** * 生成加密后的秘钥 cretkey * @return */ public static cretkey generalkey() { byte[] encodedkey = ba64.getdecoder().decode(jwtutil.jwt_key); cretkey key = new cretkeyspec(encodedkey, 0, encodedkey.length, "aes"); return key; } public static string createjwt(s河南省一本线tring id, string subject, long ttlmillis){ signaturealgorithm signaturealgorithm = signaturealgorithm.hs256; //指定签名的时候使用的签名算法,也就是header那部分,jjwt已经将这部分内容封装好了。 long nowmillis = system.currenttimemillis();//生成jwt的时间 date now = new date(nowmillis); cretkey key = generalkey();//生成签名的时候使用的秘钥cret,这个方法本地封装了的,一般可以从本地配置文件中读取,切记这个秘钥不能外露哦。它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个cret, 那就意味着客户端是可以自我签发jwt了。 jwtbuilder builder = jwts.builder() //这里其实就是new一个jwtbuilder,设置jwt的body// .tclaims(claims) //如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的 .tid(id) //设置jti(jwt id):是jwt的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。 .tissuedat(now) //iat: jwt的签发时间 .tsubject(subject) //sub(subject):代表这个jwt的主体,即它的所有人,这个是一个json格式的字符串,可以存放什么urid,roldid之类的,作为什么用户的唯一标志。 .signwith(signaturealgorithm, key);//设置签名使用的签名算法和签名使用的秘钥 if (ttlmillis >= 0) { long expmillis = nowmillis + ttlmillis; date exp = new date(expmillis); builder.texpiration(exp); //设置过期时间 } return builder.compact(); //就开始压缩为xxxxxxxxxxxxxx.xxxxxxxxxxxxxxx.xxxxxxxxxxxxx这样的jwt } public static claims parjwt(string jwt){ cretkey key = generalkey(); //签名秘钥,和生成的签名的秘钥一模一样 claims claims = jwts.parr() //得到defaultjwtparr .tsigningkey(key) //设置签名的秘钥 .parclaimsjws(jwt).getbody();//设置需要解析的jwt return claims; } public static void main(string[] args){ map<string, object> ur = new hashmap<>(); ur.put("urname", "it1995"); ur.put("password", "123456"); string jwt = createjwt(uuid.randomuuid().tostring(), json.tojsonstring(ur), 3600 * 24); system.out.println("加密后:" + jwt); //解密 claims claims = parjwt(jwt); system.out.println("解密后:" + claims.getsubject()); }}
(3)创建过滤器,用于token验证
/** * 鉴权过滤器 验证token */@componentpublic class authorizefilter implements globalfilter, ordered矫枉过正的意思 { private static final string authorize_token = "token"; @override public mono<void> filter(rverwebexchange exchange, gatewayfilterchain chain) {//1. 获取请求 rverhttprequest request = exchange.getrequest(); //2. 则获取响应 rverhttprespon respon = exchange.getrespon(); //3. 如果是登录请求则放行 if (request.geturi().getpath().contains("/admin/login")) { return chain.filter(exchange); } //4. 获取请求头 httpheaders headers = request.getheaders(); //5. 请求头中获取令牌 string toke日语等级考试报名n = headers.getfirst(authorize_token); //6. 判断请求头中是否有令牌 if (stringutils.impty(token)) { //7. 响应中放入返回的状态吗, 没有权限访问 respon.tstatuscode(httpstatus.unauthorized); //8. 返回 return respon.tcomplete(); } //9. 如果请求头中有令牌则解析令牌 try { jwtutil.parjwt(token); } catch (exception e) { e.printstacktrace(); //10. 解析jwt令牌出错, 说明令牌过期或者伪造等不合法情况出现 respon.tstatuscode(httpstatus.unauthorized); //11. 返回 return respon.tcomplete(); } //12. 放行 return chain.filter(exchange); } @override public int getorder() { return 0; }}
(4)测试:
首先进行登录测试
在进行鉴权测试
到此这篇关于springcloud中gateway实现鉴权的方法的文章就介绍到这了,更多相关springcloud gateway鉴权内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!
本文发布于:2023-04-03 23:26:45,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/3b0e09be437c28544e1814589587cb1c.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:SpringCloud中Gateway实现鉴权的方法.doc
本文 PDF 下载地址:SpringCloud中Gateway实现鉴权的方法.pdf
留言与评论(共有 0 条评论) |