1+
作为后端开发人员,我正面临着功能测试的JWT令牌过期的异常(JWTExpiredException)🤯。我认为我们很多人在日常生活编码中面临同样的问题🤬。想要出现这个问题。然后这篇文章适合你。🤩

让’在代码中潜水而不会浪费你的时间。⌚您可以从下面的Git下载代码。✨
创建JWT令牌,没有过期的春天启动
首先让’s move to the application.properties. file
1 2 3 4 5 6 7 |
jwt..秘密 = Dasjs. jwt..前任pirydateinms=50000 jwt..refreskexpirationDateinms.=9000000 春天.数据源.URL.=JDBC.:mysql.:// localhost / bootjwt?createdatabaseifnotexist = true&autoReconnect=true&useSSL=false 春天.数据源.用户名=根 春天.数据源.密码= 春天.JPA..冬眠.DDL.-汽车=创造-降低 |
我们正在使用简单的Spring Boot JWT Web令牌示例,正如您所看到的那样 jwt..expirationdateinms = 50000. 定义正常的令牌到期和 jwt..refreshexpirationdateinms = 9000000. 定义刷新令牌到期。
现在是时候使用我们的服务类(JWTUTIL)配置刷新令牌的时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
包裹 com.Dasjs..SpringBootsecurity..配置; 进口 java..利用者.阵列; 进口 java..利用者.收藏; 进口 java..利用者.日期; 进口 java..利用者.Hashmap.; 进口 java..利用者.列表; 进口 java..利用者.地图; 进口 org..Springframework..豆子.工厂.注解.价值; 进口 org..Springframework..安全.验证.BadcredentialSexception.; 进口 org..Springframework..安全.验证.用户namepasswordaeuthenticationToken.; 进口 org..Springframework..安全.核.GrantedAuthority.; 进口 org..Springframework..安全.核.权威.简单的身份奉献; 进口 org..Springframework..安全.核.用户details..用户details..; 进口 org..Springframework..刻板印象.服务; 进口 IO..jsonweptoken..索赔; 进口 IO..jsonweptoken..前任piredjwtexception.; 进口 IO..jsonweptoken..JWS.; 进口 IO..jsonweptoken..jwt.s.; 进口 IO..jsonweptoken..malformedjwtexception.; 进口 IO..jsonweptoken..signaturealgorithm.; 进口 IO..jsonweptoken..signatureexception.; 进口 IO..jsonweptoken..UNSUPPORTEDJWTException.; @服务 民众 班级 jwt.util. { 私人的 细绳 秘密; 私人的 ㈡ jwt.expordioninms.; 私人的 ㈡ refreskexpirationDateinms.; @价值(“$ {jwt.secret}”) 民众 空白 索引(细绳 秘密) { 这个.秘密 = 秘密; } @价值(“$ {jwt.expirationdateinms}”) 民众 空白 setjwtextInms.(㈡ jwt.expordioninms.) { 这个.jwt.expordioninms. = jwt.expordioninms.; } @价值(“$ {jwt.refreshexpirddatedateinms}”) 民众 空白 setRefreshexpirationDateinms.(㈡ refreskexpirationDateinms.) { 这个.refreskexpirationDateinms. = refreskexpirationDateinms.; } 民众 细绳 generateToken.(用户details.. 用户details.) { 地图<细绳, 目的> 索赔 = 新的 Hashmap.<>(); 收藏<? 延伸 GrantedAuthority.> 角色 = 用户details..得到authorities.(); 如果 (角色.包含(新的 简单的身份奉献(“角色_admin”))) { 索赔.放(“isadmin”, 真的); } 如果 (角色.包含(新的 简单的身份奉献(“角色_user”))) { 索赔.放(“威尔”, 真的); } 返回 dogenerateken.(索赔, 用户details..得到username.()); } 私人的 细绳 dogenerateken.(地图<细绳, 目的> 索赔, 细绳 主题) { 返回 jwt.s..建造者().机制(索赔).sitewject.(主题).setissuedat(新的 日期(系统.Currenttimemillis.())) .seteption.(新的 日期(系统.Currenttimemillis.() + jwt.expordioninms.)) .sign(signaturealgorithm..HS512, 秘密).袖珍的(); } 民众 细绳 dogeneraterefreshtoken.(地图<细绳, 目的> 索赔, 细绳 主题) { 返回 jwt.s..建造者().机制(索赔).sitewject.(主题).setissuedat(新的 日期(系统.Currenttimemillis.())) .seteption.(新的 日期(系统.Currenttimemillis.() + refreskexpirationDateinms.)) .sign(signaturealgorithm..HS512, 秘密).袖珍的(); } 民众 布尔基 vignateToken.(细绳 authtoken.) { 尝试 { JWS.<Claims> 索赔 = jwt.s..解析器().守则(秘密).Parseclaimsjws.(authtoken.); 返回 真的; } 抓住 (signatureexception. | malformedjwtexception. | UNSUPPORTEDJWTException | IllegalArgumentException. 前任) { 扔 新的 BadcredentialSexception.(“无效证件”, 前任); } 抓住 (前任piredjwtexception. 前任) { 扔 前任; } } 民众 细绳 得到usernamefromtoken.(细绳 令牌) { 索赔 索赔 = jwt.s..解析器().守则(秘密).Parseclaimsjws.(令牌).塔(); 返回 索赔.得到s赞许(); } 民众 列表<简单的身份奉献> 得到rolesfromtoken.(细绳 令牌) { 索赔 索赔 = jwt.s..解析器().守则(秘密).Parseclaimsjws.(令牌).塔(); 列表<简单的身份奉献> 角色 = 无效的; 布尔基 Isadmin. = 索赔.得到(“isadmin”, 布尔基.班级); 布尔基 伊斯兰人 = 索赔.得到(“威尔”, 布尔基.班级); 如果 (Isadmin. != 无效的 && Isadmin.) { 角色 = 阵列.亚文斯特(新的 简单的身份奉献(“角色_admin”)); } 如果 (伊斯兰人 != 无效的 && Isadmin.) { 角色 = 阵列.亚文斯特(新的 简单的身份奉献(“角色_user”)); } 返回 角色; } } |
现在我们必须为JWT身份验证实现过滤器。在此筛选器中命名 customjwtauthenticationfilter, 如果jwt令牌在测试期间过期,那么我们必须设置 isrefreshtoken. set to true.
创建自定义授权过滤器
当令牌到期时,我们必须从中获得索赔 前任piredjwtexception. 并将其存放在 http.request。这些索赔将用于创建刷新JWT令牌。我们必须通过创建安全上下文 用户namepasswordaeuthenticationToken. with null values.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
包裹 com.Dasjs..SpringBootsecurity..配置; 进口 java..IO..IoException.; 进口 java.x..servlet..滤波器; 进口 java.x..servlet..servlet.Exception.; 进口 java.x..servlet..http..http.servletrequest.; 进口 java.x..servlet..http..http.servletresponse.; 进口 org..Springframework..豆子.工厂.注解.自动利用; 进口 org..Springframework..安全.验证.BadcredentialSexception.; 进口 org..Springframework..安全.验证.用户namepasswordaeuthenticationToken.; 进口 org..Springframework..安全.核.语境.SecurityContextholder.; 进口 org..Springframework..安全.核.用户details..用户; 进口 org..Springframework..安全.核.用户details..用户details..; 进口 org..Springframework..刻板印象.零件; 进口 org..Springframework..利用者.stringutils.; 进口 org..Springframework..网页.筛选.丁雷德里特弗雷特; 进口 IO..jsonweptoken..前任piredjwtexception.; @零件 民众 班级 customjwtauthenticationFilter. 延伸 丁雷德里特弗雷特 { @Autowired. 私人的 jwt.util. jwt.tokentutil.; @Override. 保护 空白 dofilterinternal.(http.servletrequest. 要求, http.servletresponse. 回复, 滤波器 链) 抛出 servlet.Exception., IoException. { 尝试{ // jwt令牌处于“持卡令牌”的形式。删除承载词和 // 得到 only the Token 细绳 jwt.token. = ExtractJwtfromRequest.(要求); 如果 (stringutils..黑衣(jwt.token.) && jwt.tokentutil..vignateToken.(jwt.token.)) { 用户details.. 用户details. = 新的 用户(jwt.tokentutil..得到usernamefromtoken.(jwt.token.), “, jwt.tokentutil..得到rolesfromtoken.(jwt.token.)); 用户namepasswordaeuthenticationToken. 用户namepasswordaeuthenticationToken. = 新的 用户namepasswordaeuthenticationToken.( 用户details., 无效的, 用户details..得到authorities.()); //在上下文中设置身份验证后,我们指定 //当前用户已被身份验证。所以它通过了 // Spring Security配置成功。 SecurityContextholder..得到Context.().setauthentication.(用户namepasswordaeuthenticationToken.); } 别的 { 系统.出去.println.(“无法设置安全上下文”); } }抓住(前任piredjwtexception. 前任) { 细绳 isrefreshtoken. = 要求.Getheader.(“isrefreshtoken”); 细绳 Requesturl. = 要求.得到Requesturl.().toString.(); //如果以下条件为真,则允许刷新令牌创建。 如果 (isrefreshtoken. != 无效的 && isrefreshtoken..等于(“真的”) && Requesturl..包含(“refrestoken”)) { allowforrefreshtoken.(前任, 要求); } 别的 要求.setAttribute.(“例外”, 前任); } 抓住(BadcredentialSexception. 前任) { 要求.setAttribute.(“例外”, 前任); } 链.Dofilter.(要求, 回复); } 私人的 空白 allowforrefreshtoken.(前任piredjwtexception. 前任, http.servletrequest. 要求) { //创建具有空值的UsernamepasswordauthentationTokenToken。 用户namepasswordaeuthenticationToken. 用户namepasswordaeuthenticationToken. = 新的 用户namepasswordaeuthenticationToken.( 无效的, 无效的, 无效的); //在上下文中设置身份验证后,我们指定 //当前用户已被身份验证。所以它通过了 // Spring Security配置成功。 SecurityContextholder..得到Context.().setauthentication.(用户namepasswordaeuthenticationToken.); //将索赔设置为使其在控制器中我们将使用它来创建 //新的JWT. 要求.setAttribute.(“索赔”, 前任.得到Claims.()); } 私人的 细绳 ExtractJwtfromRequest.(http.servletrequest. 要求) { 细绳 Bearertoken. = 要求.Getheader.(“授权”); 如果 (stringutils..黑衣(Bearertoken.) && Bearertoken..以。。开始(“持票人”)) { 返回 Bearertoken..划线(7, Bearertoken..长度()); } 返回 无效的; } } |
现在我们可以移动到身份验证控制器中的“创建刷新令牌”。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
包裹 com.Dasjs..SpringBootsecurity..控制器; 进口 java..利用者.Hashmap.; 进口 java..利用者.地图; 进口 java..利用者.地图.入口; 进口 java.x..servlet..http..http.servletrequest.; 进口 org..Springframework..豆子.工厂.注解.自动利用; 进口 org..Springframework..http..响应; 进口 org..Springframework..安全.验证.身份验证管理员; 进口 org..Springframework..安全.验证.BadcredentialSexception.; 进口 org..Springframework..安全.验证.isaisablexception.; 进口 org..Springframework..安全.验证.用户namepasswordaeuthenticationToken.; 进口 org..Springframework..安全.核.用户details..用户details..; 进口 org..Springframework..网页.捆绑.注解.请求人员; 进口 org..Springframework..网页.捆绑.注解.RequestMapping.; 进口 org..Springframework..网页.捆绑.注解.要求method.; 进口 org..Springframework..网页.捆绑.注解.restcontroller.; 进口 com.Dasjs..SpringBootsecurity..配置.customuserdetailsservice.; 进口 com.Dasjs..SpringBootsecurity..配置.jwt.util.; 进口 com.Dasjs..SpringBootsecurity..模型.身份验证request.; 进口 com.Dasjs..SpringBootsecurity..模型.身份验证响应; 进口 com.Dasjs..SpringBootsecurity..模型.用户dto.; 进口 IO..jsonweptoken..拆.DefaultClaims.; @RestController. 民众 班级 身份验证控制器 { @Autowired. 私人的 身份验证管理员 身份验证管理员; @Autowired. 私人的 customuserdetailsservice. 用户details.service.; @Autowired. 私人的 jwt.util. jwt.util.; @requestmappping.(价值 = “/认证”, 方法 = 要求method..邮政) 民众 响应<?> CreateAuthenticationToken.(@请求人员 身份验证request. 身份验证request.) 抛出 例外 { 尝试 { 身份验证管理员.认证(新的 用户namepasswordaeuthenticationToken.( 身份验证request..得到username.(), 身份验证request..获取密码())); } 抓住 (isaisablexception. e) { 扔 新的 例外(“user_disabled”, e); } 抓住 (BadcredentialSexception. e) { 扔 新的 例外(“无效证件”, e); } 用户details.. 用户details. = 用户details.service..loadUserByusername.(身份验证request..得到username.()); 细绳 令牌 = jwt.util..generateToken.(用户details.); 返回 响应.好的 (新的 身份验证响应(令牌)); } @RequestMapping.(价值 = “/登记”, 方法 = 要求method..邮政) 民众 响应<?> Saptuser.(@RequestBody. 用户dto. 用户) 抛出 例外 { 返回 响应.好的 (用户details.service..保存(用户)); } @requestmappping.(价值 = “/ refreshtoken”, 方法 = 要求method..得到) 民众 响应<?> 刷新(http.servletrequest. 要求) 抛出 例外 { //从HttpRequest获得索赔 DefaultClaims. 索赔 = (IO..jsonweptoken..拆.DefaultClaims.) 要求.得到Attribute.(“索赔”); 地图<细绳, 目的> 预示图 = 得到mapfromiojsonwebthenglaims.(索赔); 细绳 令牌 = jwt.util..dogeneraterefreshtoken.(预示图, 预示图.得到(“亚”).toString.()); 返回 响应.好的 (新的 身份验证响应(令牌)); } 民众 地图<细绳, 目的> 得到mapfromiojsonwebthenglaims.(DefaultClaims. 索赔) { 地图<细绳, 目的> 预示图 = 新的 Hashmap.<细绳, 目的>(); 为了 (入口<细绳, 目的> 入口 : 索赔.进入()) { 预示图.放(入口.GetKey.(), 入口.GetValue.()); } 返回 预示图; } } |
那’它。现在,您可以检查此示例的演示。
演示屏幕截图
注册用户

验证URL.

使用普通令牌访问管理部分

创建刷新令牌

下载源代码
1+