为什么Auth0不抛出403与spring-boot-start -oauth2-resource-server时,过滤



我有以下内容…

@RestController
@RequestMapping(path="/person", produces = MediaType.APPLICATION_JSON_VALUE)
public class AuthController {
@GetMapping("")
@ResponseBody
public String getPersonFromEmail(@RequestParam(name = "email") String email){ ... }
}
@EnableWebSecurity
public class SecurityConfig {
...
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests()
.requestMatchers("/person").hasAuthority("SCOPE_blahablah")
.anyRequest().authenticated()
.and().cors()
.and().oauth2ResourceServer().jwt();
return http.build();
}
}

当我运行但不传递令牌时,我得到401。然而,当我传递一个没有适当作用域的令牌时,我得到一个200。我也希望能得到403分。我错过了什么?

再深入一点,看起来问题是查询参数。不知道如何协调那些…

~/tmp/user-profile >curl -v http://localhost:8080/person
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /person HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.85.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 403 
< Set-Cookie: JSESSIONID=EFD9C400D91760FE8FA2119AC2EB382B; Path=/; HttpOnly
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 0
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Length: 0
< Date: Wed, 11 Jan 2023 21:45:16 GMT
< 
* Connection #0 to host localhost left intact
~/tmp/user-profile >curl -v http://localhost:8080/person?email=...
zsh: no matches found: http://localhost:8080/person?email=... <-- This means it worked without checking

首先,Auth0只发出访问令牌,它不会对API中的访问控制决策进行评估。你的问题是你的资源服务器的Spring web安全配置(授权服务器是Auth0并不重要)。

第二,你应该期待的实际上是一个403(禁止,这意味着身份验证是有效的,但访问被拒绝),而不是401(未授权,这意味着身份验证缺失或无效)。

您是否检查了您的SecurityConfig是否正确加载了断点或日志行?似乎@Configuration丢失了,我打赌你的资源服务器实际上是用spring-boot默认的SecurityFilterChain保护的,它只适用于anyRequest().authenticated()

您还可以禁用会话(和CSRF保护)。由于CSRF保护,访问可能会被拒绝,当会话被禁用并且访问令牌很少需要会话时,CSRF保护是无用的。它还可以简化扩展和容错性。

你可以看看我的关于资源服务器配置和访问控制测试的教程。

编辑:完整样本

package com.c4soft.dumb;
import java.util.Arrays;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
@SpringBootApplication
public class DumbApplication {
public static void main(String[] args) {
SpringApplication.run(DumbApplication.class, args);
}
@RestController
@RequestMapping(path = "/dumb")
public class AuthController {
@GetMapping("/public")
public String getPublic() {
return "Hello!";
}
@GetMapping("/person")
public String getPersonFromEmail(@RequestParam(name = "email") String email) {
return email;
}
@GetMapping("/name")
public String getName(Authentication auth) {
return auth.getName();
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.oauth2ResourceServer().jwt();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().csrf().disable();
// @formatter:off
http.authorizeHttpRequests()
.requestMatchers("/dumb/public").permitAll()
.requestMatchers("/dumb/person").hasAuthority("SCOPE_email")
.anyRequest().authenticated();
// @formatter:on
http.cors().configurationSource(corsConfigurationSource());

return http.build();
}
private CorsConfigurationSource corsConfigurationSource() {
final var configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setExposedHeaders(Arrays.asList("*"));
final var source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/dumb/**", configuration);
return source;
}
}
}
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://dev-ch4mpy.eu.auth0.com/

对Postman的查询完全按照预期工作:

  • http://localhost:8080/dumb/public无需任何认证即可访问
  • http://localhost:8080/dumb/name返回
    • 401如果访问令牌缺失或无效(错误的颁发者,过期,…)
    • access-tokensub声明值,如果访问令牌有效
  • http://localhost:8080/dumb/person?email=dumb@truc.com返回
    • 401如果访问令牌缺失或无效(错误的颁发者,过期,…)
    • 403如果客户端没有请求emailscope
    • dumb@truc.com如果访问令牌是有效的,并且具有email范围

最新更新