首頁  >  文章  >  使用 OAuth 2.0 資源伺服器 JWT 時出現權限(授權)問題

使用 OAuth 2.0 資源伺服器 JWT 時出現權限(授權)問題

WBOY
WBOY轉載
2024-02-13 15:51:09923瀏覽

在使用 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.eyjpc3mioijzchjpbmctc2vjdxjpdhktand0iiwic3ljoidxnlcm5hbwuilcjlehaioje3mdu0ndmyqxdwniiFw^motcaiwoodiwoodiwoo; eefqbid5dplhffzcvd7scmmt3f7rk7sk1i6kerpqi5ubdvaefnzsjq6vka5nadltsbqidfzogmoixjktfhsc5zrnyyrhikvnwcwb3wrgdd1gihaldfjktfhsc5zrnyyrhikvnwcwb3wrgdd1m zk3gqw42uecib9h1rrlkx9pdk7pf9rtfssfcwc-ntvismrycreco9rialqfydpdzeojimcbqveyboqfhn2woepgdm8mr5zsdhgdq e1ivsibbcj_0486zuzuqik>p25zsdhgd

安全性設定:#

@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() 中,您嘗試將 setAuthorityPrefixROLE 一起使用,導致 ROLE_ROLE_ADMIN

要修正此問題,請將該行修改為

grantedAuthoritiesConverter.setAuthorityPrefix("");

進行此調整後,問題應該得到解決。如果您遇到任何其他問題,請告訴我。

注意:

如果省略此步驟,預設前綴將為

SCOPE,導致您的角色變為 SCOPE_ROLE_ADMIN

以上是使用 OAuth 2.0 資源伺服器 JWT 時出現權限(授權)問題的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除