在使用 OAuth 2.0 资源服务器 JWT 时,有时会遇到权限(授权)问题。这是许多开发人员在开发过程中经常遇到的一个挑战。OAuth 2.0 是一种用于授权的开放标准,它允许用户授权第三方应用访问其受保护的资源。JWT(JSON Web Token)是一种用于在网络应用之间传递声明的方式。然而,在实践中,可能会出现一些权限问题,比如授权失败、无法获取访问令牌等。本文将针对这些问题进行解析,并提供一些解决方案,帮助开发人员更好地使用 OAuth 2.0 资源服务器 JWT。
我正在尝试使用 oauth 2.0 资源服务器 jwt 在一个简单的应用程序中使用 jwt 配置访问授权。
整个身份验证部分工作正常,但我在授权方面遇到问题。即使令牌中存在正确的权限,所有受保护的端点也会给出 403 forbidden
错误。
我尝试使用默认范围(scope_)属性并将配置更改为角色(role_),但问题仍然存在。
有谁知道怎么解决吗?
完整源代码: https://github.com/gustavosc1/spring-security-jwt
生成令牌示例: eyjhbgcioijsuzi1nij9.eyjpc3mioijzchjpbmctc2vjdxjpdhktand0iiwic3viijoidxnlcm5hbwuilcjlehaioje3mdu0ndmyotqsimlhdci6mtcwntqwnzi5ncwicm9szxmi oijst0xfx0fetuloin0.peivwrthx_7mr6eefqbid5dplhffzcvd7scmmt3f7rk7sk1i6kerpqi5ubdvaefnzsjq6vka5nadltsbqidfzogmoixjktfhsc5zrnyyrhikvnwcwb3wrgdd1ezgihaldfjxwxsyypau njwdxznirkl93e6mg1uao5piy9p-9yp8jer7o31wkdr1coskzk3gqw42uecib9h1rrlkx9pdk7pf9rtfssfcwc-ntvismrycreco9rialqfydpdzeojimcbqveyboqfhn2woepgdm8mr5zsdhgdq e1ivsibfbcj_0486zuqiksxp2kniljhl2b5qnan07fjpvslk--ccsg
安全配置:
@configuration @enablewebsecurity //@enablemethodsecurity(prepostenabled = true) public class securityconfig { @value("${jwt.public.key}") private rsapublickey key; @value("${jwt.private.key}") private rsaprivatekey priv; @bean securityfilterchain filterchain(httpsecurity http) throws exception { http.csrf(csrf -> csrf.disable()) .authorizehttprequests( auth -> auth .requestmatchers("/authenticate").permitall() .requestmatchers("/register").permitall() .requestmatchers("/private").hasanyrole("admin")) .httpbasic(customizer.withdefaults()) // https://docs-spring-io.translate.goog/spring-security/reference/servlet/oauth2/resource-server/jwt.html?_x_tr_sl=en&_x_tr_tl=pt&_x_tr_hl=pt-br&_x_tr_pto=sc .oauth2resourceserver( conf -> conf.jwt( jwt -> jwt.decoder(jwtdecoder()) .jwtauthenticationconverter(jwtauthenticationconverter()))); return http.build(); } @bean public jwtauthenticationconverter jwtauthenticationconverter() { jwtgrantedauthoritiesconverter grantedauthoritiesconverter = new jwtgrantedauthoritiesconverter(); grantedauthoritiesconverter.setauthoritiesclaimname("roles"); grantedauthoritiesconverter.setauthorityprefix("role_"); jwtauthenticationconverter jwtauthenticationconverter = new jwtauthenticationconverter(); jwtauthenticationconverter.setjwtgrantedauthoritiesconverter(grantedauthoritiesconverter); return jwtauthenticationconverter; } @bean jwtdecoder jwtdecoder() { return nimbusjwtdecoder.withpublickey(this.key).build(); } @bean jwtencoder jwtencoder() { jwk jwk = new rsakey.builder(this.key).privatekey(this.priv).build(); jwksource<securitycontext> jwks = new immutablejwkset<>(new jwkset(jwk)); return new nimbusjwtencoder(jwks); } @bean passwordencoder passwordencoder() { return new bcryptpasswordencoder(); } }
userdetailsserviceimpl:
@service public class userdetailsserviceimpl implements userdetailsservice { private final userrepository userrepository; public userdetailsserviceimpl(userrepository userrepository) { this.userrepository = userrepository; } @override public userdetails loaduserbyusername(string username) throws usernamenotfoundexception { optional<user> useroptional = userrepository.findbyusername(username); user user = useroptional.orelsethrow(() -> new usernamenotfoundexception("user not found with username: " + username)); return new userauthenticated(user.getusername(), user.getpassword()); } }
用户已验证:
public class userauthenticated implements userdetails { private string username; private string password; public userauthenticated(string username, string password) { this.username = username; this.password = password; } @override public string getusername() { return username; } @override public string getpassword() { return password; } @override public collection<? extends grantedauthority> getauthorities() { return list.of(() -> "role_admin"); } @override public boolean isaccountnonexpired() { return true; } @override public boolean isaccountnonlocked() { return true; } @override public boolean iscredentialsnonexpired() { return true; } @override public boolean isenabled() { return true; } }
jwtservice:
@service public class jwtservice { private final jwtencoder encoder; public jwtservice(jwtencoder encoder) { this.encoder = encoder; } public string generatetoken(authentication authentication) { instant now = instant.now(); long expiry = 36000l; string scope = authentication .getauthorities().stream() .map(grantedauthority::getauthority) .collect(collectors .joining(" ")); jwtclaimsset claims = jwtclaimsset.builder() .issuer("spring-security-jwt") .issuedat(now) .expiresat(now.plusseconds(expiry)) .subject(authentication.getname()) .claim("roles", scope) .build(); return encoder.encode( jwtencoderparameters.from(claims)) .gettokenvalue(); } }
私人控制器:
@RestController @RequestMapping("private") public class PrivateController { @GetMapping //@PreAuthorize("hasAuthority('ROLE_ADMIN')") public String getMessage() { return "Hello from private API controller"; } }
已生成提供的令牌,并将 roles
字段设置为 ROLE_ADMIN
。在 jwtAuthenticationConverter()
中,您尝试将 setAuthorityPrefix
与 ROLE
一起使用,导致 ROLE_ROLE_ADMIN
。
要纠正此问题,请将该行修改为 grantedAuthoritiesConverter.setAuthorityPrefix("");
。
进行此调整后,问题应该得到解决。如果您遇到任何其他问题,请告诉我。
注意:
如果省略此步骤,默认前缀将为 SCOPE
,导致您的角色变为 SCOPE_ROLE_ADMIN
。
以上是使用 OAuth 2.0 资源服务器 JWT 时出现权限(授权)问题的详细内容。更多信息请关注PHP中文网其他相关文章!