Spring Security OAuth2 在 REST 服务上被拒绝访问
Posted
技术标签:
【中文标题】Spring Security OAuth2 在 REST 服务上被拒绝访问【英文标题】:Spring Security OAuth2 get Access Denied on REST Service 【发布时间】:2019-05-17 08:38:11 【问题描述】:我正在尝试使用 Spring 安全性和 OAuth2 来保护我的 Spring REST 服务。我设法得到了令牌:
tokens
但是当我尝试获得安全的休息服务时,我的访问被拒绝:
denied
谁能告诉我为什么会这样?
授权服务器配置:
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter
private static String REALM="EXAMPLE_REALM";
@Autowired
private TokenStore tokenStore;
@Autowired
private UserApprovalHandler handler;
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception
clients.inMemory()
.withClient("myRestClient") // client id
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust")
.secret("noopP@ssw0rd")
.accessTokenValiditySeconds(240).//invalid after 4 minutes.
refreshTokenValiditySeconds(600);//refresh after 10 minutes.
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception
endpoints.tokenStore(tokenStore).userApprovalHandler(handler)
.authenticationManager(authManager);
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception
oauthServer.realm(REALM+"/client");
资源服务器配置:
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter
private static final String RESOURCE_ID = "SPRING_REST_API";
@Override
public void configure(ResourceServerSecurityConfigurer resources)
resources.resourceId(RESOURCE_ID).stateless(false);
@Override
public void configure(HttpSecurity http) throws Exception
http.
anonymous().disable()
.requestMatchers().antMatchers("/api/**")
.and().authorizeRequests()
.antMatchers("/api/**").access("hasRole('ADMIN')")
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
安全配置:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Autowired
private ClientDetailsService clientService;
@Bean
public PasswordEncoder passwordEncoder()
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception
auth
.inMemoryAuthentication()
.withUser("user")
.password(passwordEncoder().encode("password"))
.roles("USER")
.and()
.withUser("admin")
.password(passwordEncoder().encode("admin"))
.roles("ADMIN");
@Override
protected void configure(HttpSecurity http) throws Exception
http
.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/oauth/token").permitAll()
.antMatchers("/about").authenticated();
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception
return super.authenticationManagerBean();
@Bean
public TokenStore tokenStore()
return new InMemoryTokenStore();
@Bean
@Autowired
public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore)
TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
handler.setTokenStore(tokenStore);
handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientService));
handler.setClientDetailsService(clientService);
return handler;
@Bean
@Autowired
public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
AboutController(休息服务):
@RestController
public class AboutController
@RequestMapping(value = "/about", method = RequestMethod.GET)
public ResponseEntity<?> home()
return new ResponseEntity<>("This is a demo application to show how to secure REST API using Spring Security and OAuth2", HttpStatus.OK);
application.properties:
server.servlet.context-path=/api
security.oauth2.resource.filter-order = 3
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-rest-service</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
提前致谢!
【问题讨论】:
一目了然:您的内存中身份验证定义了ROLE_CLIENT
,但您的端点正在寻找ROLE_ADMIN
。
替代方案:如果您将令牌作为承载者放在Authorization
标头中会发生什么?所以看起来像Authorization: Bearer <UUID>
。将令牌作为查询参数传递到您的 URL 中似乎很尴尬并且可能损坏,因此理想情况下不需要存在...
【参考方案1】:
得到了这个工作。我的问题是我在 application.config 文件中添加了 /api 以便我的所有服务都有一个 api 文件夹,例如:http://localhost:8080/api/about .. 在我的 ResourceServerConfig 类中,我添加了 /api/** 作为 requestMatchers 和 antMatchers .... sercurity 配置正在此 api 前缀文件夹之后寻找 serverice .... 所以公开我的 about rest 完成这样:
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter
private static final String RESOURCE_ID = "SPRING_REST_API";
@Override
public void configure(ResourceServerSecurityConfigurer resources)
resources.resourceId(RESOURCE_ID).stateless(false);
@Override
public void configure(HttpSecurity http) throws Exception
http.
anonymous().disable()
.requestMatchers().antMatchers("/about/**")
.and().authorizeRequests()
.antMatchers("/about/**").access("hasRole('ADMIN')")
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
顺便说一句..我可以使用请求屏幕截图中的参数请求 about 服务,但如果我提供授权令牌也可以作为承载令牌授权标头....
问候!
彼得
【讨论】:
以上是关于Spring Security OAuth2 在 REST 服务上被拒绝访问的主要内容,如果未能解决你的问题,请参考以下文章
oauth2 spring-security 如果您在请求令牌或代码之前登录
使用 spring-session 和 spring-cloud-security 时,OAuth2ClientContext (spring-security-oauth2) 不会保留在 Redis
Spring-Security OAuth2 设置 - 无法找到 oauth2 命名空间处理程序
Spring Security OAuth2 v5:NoSuchBeanDefinitionException:'org.springframework.security.oauth2.jwt.Jwt