收到“权限不足”错误,尽管我有足够的权限。

huangapple go评论54阅读模式
英文:

Recieve "Insufficient scope" error even though i have sufficient one

问题

Here's the translated content:

实现JWT令牌身份验证,使用OAuth2ResourceServer(Spring 3)

spring安全配置:

@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@Configuration
@RequiredArgsConstructor
public class SpringSecurityConfig {
    private final AuthenticationService authenticationService;
    private final PasswordEncoder passwordEncoder;
    private final RsaProperties rsaKeys;

    @Bean
    public AuthenticationManager authManager() {
        var authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(authenticationService);
        authProvider.setPasswordEncoder(passwordEncoder);
        return new ProviderManager(authProvider);
    }

    @Bean
    public JwtEncoder jwtEncoder() {
        JWK jwk = new RSAKey.Builder(rsaKeys.publicKey()).privateKey(rsaKeys.privateKey()).build();
        JWKSource<SecurityContext> jwkSource = new ImmutableJWKSet<>(new JWKSet(jwk));
        return new NimbusJwtEncoder(jwkSource);
    }

    @Bean
    public JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder.withPublicKey(rsaKeys.publicKey()).build();
    }

    @Bean
    public JwtTokenService tokenService() {
        return new JwtTokenService(jwtEncoder());
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity
                .csrf().disable()
                .authorizeHttpRequests()
                .requestMatchers("/authentication/login").permitAll()
                .requestMatchers("/credit/request").hasAuthority("SCOPE_usr")
                .and()
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
                .build();
    }
}

JwtTokenService:

@Component
@RequiredArgsConstructor
public class JwtTokenService {
    private final JwtEncoder jwtEncoder;

    public String generateAccessToken(UserDetailsEntity userDetails) {
        Instant now = Instant.now();
        String scope = userDetails.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.joining(" "));

        JwtClaimsSet claims = JwtClaimsSet.builder()
                .issuer("self")
                .issuedAt(now)
                .expiresAt(now.plus(2, ChronoUnit.HOURS))
                .subject(userDetails.getUsername())
                .claim("scope", scope)
                .build();
        return this.jwtEncoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();
    }

    public String generateRefreshToken(UserDetailsEntity userDetails) {
        Instant now = Instant.now();
        String scope = userDetails.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.joining(" "));

        JwtClaimsSet claims = JwtClaimsSet.builder()
                .issuer("self")
                .issuedAt(now)
                .expiresAt(now.plus(10, ChronoUnit.HOURS))
                .subject(userDetails.getUsername())
                .claim("scope", scope)
                .build();
        return this.jwtEncoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();
    }

    public String parseToken(String token) {
        try {
            SignedJWT decodedJwt = SignedJWT.parse(token);
            return decodedJwt.getJWTClaimsSet().getSubject();
        } catch (ParseException e) {
            System.out.println(e.getStackTrace());
        }
        return null;
    }
}

因此,我的令牌包含声明“scope”,其值为“SCOPE_usr”,在“/credit/request”端点上需要,尽管服务器继续响应403错误代码和“权限不足”的消息。我尝试在JwtTokenService中硬编码范围为“SCOPE_usr”,以便所有我的令牌通过端点检查(我明白这可能听起来很愚蠢,但在这一刻,这是我认为OAuth2服务器工作的方式)。有人可以解释一下OAuth2ResourceServer如何检查范围的方式,以及我应该尝试修复问题的方法吗?

英文:

Implementing authentication via JWT token, using OAuth2ResourceServer (Spring 3)

spring security config:

@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@Configuration
@RequiredArgsConstructor
public class SpringSecurityConfig {
private final AuthenticationService authenticationService;
private final PasswordEncoder passwordEncoder;
private final RsaProperties rsaKeys;
@Bean
public AuthenticationManager authManager() {
var authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(authenticationService);
authProvider.setPasswordEncoder(passwordEncoder);
return new ProviderManager(authProvider);
}
@Bean
public JwtEncoder jwtEncoder() {
JWK jwk = new RSAKey.Builder(rsaKeys.publicKey()).privateKey(rsaKeys.privateKey()).build();
JWKSource&lt;SecurityContext&gt; jwkSource = new ImmutableJWKSet&lt;&gt;(new JWKSet(jwk));
return new NimbusJwtEncoder(jwkSource);
}
@Bean
public JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withPublicKey(rsaKeys.publicKey()).build();
}
@Bean
public JwtTokenService tokenService() {
return new JwtTokenService(jwtEncoder());
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
return httpSecurity
.csrf().disable()
.authorizeHttpRequests()
.requestMatchers(&quot;/authentication/login&quot;).permitAll()
.requestMatchers(&quot;/credit/request&quot;).hasAuthority(&quot;SCOPE_usr&quot;)
.and()
.sessionManagement(session -&gt; session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.oauth2ResourceServer(OAuth2ResourceServerConfigurer :: jwt )
.build();
}
}

JwtTokenService:

@Component
@RequiredArgsConstructor
public class JwtTokenService {
private final JwtEncoder jwtEncoder;
public String generateAccessToken(UserDetailsEntity userDetails) {
Instant now = Instant.now();
String scope = userDetails.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(&quot; &quot;));
JwtClaimsSet claims = JwtClaimsSet.builder()
.issuer(&quot;self&quot;)
.issuedAt(now)
.expiresAt(now.plus(2, ChronoUnit.HOURS))
.subject(userDetails.getUsername())
.claim(&quot;scope&quot;, scope)
.build();
return this.jwtEncoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();
}
public String generateRefreshToken(UserDetailsEntity userDetails) {
Instant now = Instant.now();
String scope = userDetails.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(&quot; &quot;));
JwtClaimsSet claims = JwtClaimsSet.builder()
.issuer(&quot;self&quot;)
.issuedAt(now)
.expiresAt(now.plus(10, ChronoUnit.HOURS))
.subject(userDetails.getUsername())
.claim(&quot;scope&quot;, scope)
.build();
return this.jwtEncoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();
}
public String parseToken(String token) {
try {
SignedJWT decodedJwt = SignedJWT.parse(token);
return decodedJwt.getJWTClaimsSet().getSubject();
} catch (ParseException e) {
System.out.println(e.getStackTrace());
}
return null;
}
}

So my tokens contains claim "scope" with value "SCOPE_usr" which required on "/credit/request" endpoint, even though server continues to response with 403 code error and "insufficient scope" message. I tried to hardcode scope to "SCOPE_usr" in JwtTokenService, so all my tokens pass the endpoint check (I understand, that it may sound stupid, but at this moment that's the way I think OAuth2 server works). Can somebody explain, which way OAuth2ResourceServer checks scopes, and what should I try to fix that problem?

答案1

得分: 1

你正在使用默认的权限转换器,该转换器接受范围声明条目并在其前加上“SCOPE_”前缀。使用此转换器和您在配置中拥有的requestMatchers访问规则,令牌中的范围应为usr(将被转换为SCOPE_usr权限)。

英文:

You are using the default authorities converter which takes scope claim entries and adds SCOPE_ prefix to it. With this converter and the requestMatchers access rules you have in your conf, the scope in the token should be usr (which will be converted to SCOPE_usr authority).

huangapple
  • 本文由 发表于 2023年5月10日 23:38:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/76220318.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定