我的Spring Boot项目中有一个相当基本的设置。我正在尝试设置OAuth2来保护我的API,但是我遇到了/oauth/token端点问题。向我的/oauth/token端点发出POST或GET请求将导致以下响应(带有401 Unauthorized状态代码):
/oauth/token
401 Unauthorized
{ "timestamp": "2018-09-17T16:46:59.961+0000", "status": 401, "error": "Unauthorized", "message": "Unauthorized", "path": "/oauth/token" }
这是我的授权服务器配置。
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; import org.springframework.security.oauth2.provider.approval.UserApprovalHandler; import org.springframework.security.oauth2.provider.token.TokenStore; @Configuration @EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private TokenStore tokenStore; @Autowired private UserApprovalHandler userApprovalHandler; @Autowired @Qualifier("authenticationManagerBean") private AuthenticationManager authenticationManager; @Autowired private PasswordEncoder passwordEncoder; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("client_id") .secret("secret") .authorizedGrantTypes("password", "authorization_code", "refresh_token") .scopes("read", "write") .accessTokenValiditySeconds(600) .refreshTokenValiditySeconds(3600); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.tokenStore(this.tokenStore) .userApprovalHandler(this.userApprovalHandler) .authenticationManager(this.authenticationManager); } @Override public void configure(AuthorizationServerSecurityConfigurer security) { security.tokenKeyAccess("permitAll()") .checkTokenAccess("isAuthenticated()") .passwordEncoder(this.passwordEncoder); } }
这是我的资源服务器配置。尚无重要信息:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.TokenStore; public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Autowired private TokenStore tokenStore; @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.tokenStore(this.tokenStore); } }
最后是我的标准Web安全配置:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.provider.ClientDetailsService; import org.springframework.security.oauth2.provider.approval.ApprovalStore; import org.springframework.security.oauth2.provider.approval.TokenApprovalStore; import org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler; import org.springframework.security.oauth2.provider.approval.UserApprovalHandler; import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private ClientDetailsService clientDetailsService; @Autowired public void globalUserDetails(AuthenticationManagerBuilder builder) throws Exception { builder.inMemoryAuthentication() .withUser("user").password("password").roles("ADMIN") .and() .withUser("admin").password("password").roles("USER"); } @Override protected void configure(HttpSecurity security) throws Exception { security.csrf().disable() .anonymous().disable() .authorizeRequests() .antMatchers("/oauth/token").permitAll(); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Bean public TokenStore tokenStore() { return new InMemoryTokenStore(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(8); } @Bean @Autowired public UserApprovalHandler userApprovalHandler(TokenStore tokenStore) { TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler(); handler.setTokenStore(tokenStore); handler.setRequestFactory(new DefaultOAuth2RequestFactory(this.clientDetailsService)); handler.setClientDetailsService(this.clientDetailsService); return handler; } @Bean @Autowired public ApprovalStore approvalStore(TokenStore tokenStore) { TokenApprovalStore store = new TokenApprovalStore(); store.setTokenStore(tokenStore); return store; } }
我已经用不同的匹配器模式弄乱了很多,以查看是否可以使它工作,但我没有任何运气。我在根上下文和上的servlet路径中运行此文件http://localhost:8080。
http://localhost:8080
我可以确认,当Spring Boot启动时,端点已映射到输出中,尝试达到稍有不同的端点将导致预期的404。
原来我没有正确地到达终点。我正在通过HTTP POST发送所有数据,包括客户端凭据。
POST http://localhost:8080/oauth/token ... client_id=client_id&secret=secret&scope=read&grant_type=password&username=user&password=password
我需要使用HTTP基本身份验证发送我的客户端凭据,而不是发布它们:
POST http://localhost:8080/oauth/token Authorization: Basic Y2xpZW50X2lkOnNlY3JldA== ... scope=read&grant_type=password&username=user&password=password