Java Spring OAuth2“访问此资源需要完整身份验证”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23950068/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring OAuth2 "Full authentication is required to access this resource"
提问by Alex
I'm trying to use Spring OAuth2 for my rest app. But looks like I made a mistake and I can find where I did it. The flow should be: 1. get token from /oauth/token with username and password 2. make request to /security with provided token
我正在尝试将 Spring OAuth2 用于我的休息应用程序。但看起来我犯了一个错误,我可以找到我在哪里做的。流程应该是: 1. 使用用户名和密码从 /oauth/token 获取令牌 2. 使用提供的令牌向 /security 发出请求
MethodSecurityConfig:
方法安全配置:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Autowired
private SecurityConfiguration securityConfig;
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
OAuth2ServerConfig:
OAuth2ServerConfig:
@Configuration
public class OAuth2ServerConfig {
private static final String RESOURCE_ID = "nessnity";
@Configuration
@Order(10)
protected static class UiResourceConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/security")
.and()
.authorizeRequests()
.antMatchers("/security").access("hasRole('USER')");
}
}
@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/security/")
.and()
.authorizeRequests()
.antMatchers("/security").access("#oauth2.hasScope('read')");
}
}
@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Autowired
private UserApprovalHandler userApprovalHandler;
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("my-client")
.resourceIds(RESOURCE_ID)
.authorizedGrantTypes("client_credentials")
.authorities("ROLE_CLIENT")
.scopes("read")
.secret("password")
.accessTokenValiditySeconds(60);
}
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(tokenStore)
.userApprovalHandler(userApprovalHandler)
.authenticationManager(authenticationManager);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.realm("sparklr2/client");
}
}
protected static class Stuff {
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
private TokenStore tokenStore;
@Bean
public ApprovalStore approvalStore() throws Exception {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
}
@Bean
@Lazy
@Scope(proxyMode=ScopedProxyMode.TARGET_CLASS)
public SparklrUserApprovalHandler userApprovalHandler() throws Exception {
SparklrUserApprovalHandler handler = new SparklrUserApprovalHandler();
handler.setApprovalStore(approvalStore());
handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
handler.setClientDetailsService(clientDetailsService);
handler.setUseApprovalStore(true);
return handler;
}
}
}
SecurityConfiguration:
安全配置:
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("root")
.password("password")
.roles("USER");
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/oauth/uncache_approvals", "/oauth/cache_approvals");
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().hasRole("USER");
}
}
Problem: when I tried to get token
问题:当我尝试获取令牌时
curl --user root:password --data "grant_type=client_credentials" http://localhost:8080/oauth/token
I got message:
我收到消息:
{"error":"invalid_client","error_description":"Bad client credentials"}
{"error":"invalid_client","error_description":"错误的客户端凭据"}
The second question is how to pass username/password in the url params like /oauth/token?username=root&password=password ?
第二个问题是如何在像 /oauth/token?username=root&password=password 这样的 url 参数中传递用户名/密码?
Thanks.
谢谢。
UPDATE
更新
I decided to start from scratch and use xml configuration.
我决定从头开始并使用 xml 配置。
The following configuration works perfect:
以下配置完美运行:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<http pattern="/oauth/token" create-session="stateless"
authentication-manager-ref="authenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY"/>
<anonymous enabled="false"/>
<http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
<custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER"/>
<access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
<authentication-manager alias="authenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService"/>
</authentication-manager>
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails"/>
</bean>
<bean id="clientDetails" class="com.nessnity.api.security.OAuthClienDetailsService">
<property name="id" value="testuser"/>
<property name="secretKey" value="secret" />
</bean>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="springsec/client"/>
<property name="typeName" value="Basic"/>
</bean>
<bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>
<oauth:authorization-server
client-details-service-ref="clientDetails"
token-services-ref="tokenServices">
<oauth:authorization-code/>
<oauth:implicit/>
<oauth:refresh-token/>
<oauth:client-credentials/>
<oauth:password authentication-manager-ref="userAuthenticationManager"/>
</oauth:authorization-server>
<authentication-manager id="userAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider ref="customUserAuthenticationProvider">
</authentication-provider>
</authentication-manager>
<bean id="customUserAuthenticationProvider"
class="com.nessnity.api.security.OAuthUserAuthenticationProvider">
</bean>
<bean id="tokenServices"
class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore"/>
<property name="supportRefreshToken" value="true"/>
<property name="accessTokenValiditySeconds" value="900000000"/>
<property name="clientDetailsService" ref="clientDetails"/>
</bean>
<bean id="tokenStore"
class="org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore"/>
<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
</bean>
<http pattern="/resources/**" create-session="never"
entry-point-ref="oauthAuthenticationEntryPoint"
xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false"/>
<intercept-url pattern="/resources/**" method="GET"/>
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER"/>
<access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>
<oauth:resource-server id="resourceServerFilter"
resource-id="springsec" token-services-ref="tokenServices"/>
</beans>
回答by Jayasagar
I have faced similar for me it worked after doing the following change
我遇到了类似的情况,在进行以下更改后它起作用了
In your AuthorizationServerConfigurationclass replace
在您的AuthorizationServerConfiguration类中替换
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.realm("sparklr2/client");
}
with the below code
使用以下代码
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
//oauthServer.realm("sparklr2/client");
oauthServer.allowFormAuthenticationForClients();
}
and request should like
和请求应该喜欢
/oauth/token?grant_type=password&scope=read+write&client_id=yourclientId&client_secret=secret&username=userName&password=pwd
/oauth/token?grant_type=password&scope=read+write&client_id=yourclientId&client_secret=secret&username=userName&password=pwd
回答by Imrank
In your access token request you are using client credentials grant type. OAuth spec says that in case of client_credentials grant type you need to provide base64 encoded client_id:client_secret
as Basic Authorization header.
For example if your client_id is google
and client_secret is x23r-ss56-rfg8-6yt6
, then you need to add these string as google:x23r-ss56-rfg8-6yt6
, encode it using Base64 encoder and make request as
在您的访问令牌请求中,您使用的是客户端凭据授权类型。OAuth 规范说,在 client_credentials 授权类型的情况下,您需要提供 base64 编码client_id:client_secret
为 Basic Authorization 标头。例如,如果您的 client_id 是google
并且 client_secret 是x23r-ss56-rfg8-6yt6
,那么您需要将这些字符串添加为google:x23r-ss56-rfg8-6yt6
,使用 Base64 编码器对其进行编码并将请求作为
curl --header "Authorization: Basic <base64 encoded_string>" --data "grant_type=client_credentials" http://localhost:8080/oauth/token