java Spring Oauth2:在 SecurityContext 中找不到身份验证对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/43247940/
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 : Authentication Object was not found in the SecurityContext
提问by subash048
I have a project where i implement Spring security and Spring OAuth2 Security.When i request for access token it works well but when i request for resource using access token i got 'An authentication object was not found in the SecurityContext'.
我有一个项目,我在其中实现了 Spring 安全性和 Spring OAuth2 安全性。当我请求访问令牌时,它运行良好,但是当我使用访问令牌请求资源时,我得到“在 SecurityContext 中找不到身份验证对象”。
SecurityContext of my project is :
我的项目的 SecurityContext 是:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:oauth2="http://www.springframework.org/schema/security/oauth2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<global-method-security jsr250-annotations="enabled" />
<http pattern="/**/*.css" security="none" />
<http pattern="/**/*.css.map" security="none" />
<http pattern="/**/*.gif" security="none" />
<http pattern="/**/*.html" security="none" />
<http pattern="/**/*.ttf" security="none" />
<http pattern="/**/*.eot" security="none" />
<http pattern="/**/*.svg" security="none" />
<http pattern="/**/*.woff" security="none" />
<http pattern="/**/*.woff2" security="none" />
<http pattern="/**/*.xls" security="none" />
<http pattern="/**/*.ico" security="none" />
<http pattern="/**/*.jpg" security="none" />
<http pattern="/**/*.js" security="none" />
<http pattern="/**/*.png" security="none" />
<http pattern="/**/*.xml" security="none" />
<http pattern="/**/*.mp4" security="none" />
<http pattern="editCustomerTrnx" security="none"/>
<!--<http pattern="/embed/*" security="none"/> -->
<!-- Default URL provided by spring to get the token(access and refresh) from oauth -->
<http pattern="/oauth/token" create-session="never"
authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY"/>
<http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
<!-- Using this to authenticate client using request parameter -->
<custom-filter ref="clientCredentialsTokenEndPointFilter" after="BASIC_AUTH_FILTER"/>
<access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>
<!-- The OAuth2 protected resources are separated out into their own block so we can deal with authorization and error handling
separately. This isn't mandatory, but it makes it easier to control the behaviour -->
<http pattern="/Api/**" create-session="stateless" entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager"
xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false"/>
<intercept-url pattern="/Api/**" access="ROLE_ADMIN"/>
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>
<!-- 2 -->
<http auto-config="true">
<intercept-url pattern="/Admin/**"
access="ROLE_ADMINISTRATOR,ROLE_AUTHENTICATED" requires-channel="any" />
<intercept-url pattern="/Seller/**" access="ROLE_AUTHENTICATED,ROLE_SELLER"
requires-channel="any" />
<intercept-url pattern="/login/**" access="IS_AUTHENTICATED_ANONYMOUSLY"
requires-channel="any" />
<intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY"
requires-channel="any" />
<!-- <remember-me key="remittancerm" /> -->
<custom-filter position="CONCURRENT_SESSION_FILTER" ref="customSessionFilter" />
<form-login login-page="/main"
authentication-failure-handler-ref="failureHandler"
always-use-default-target="false" default-target-url="/"
authentication-success-handler-ref="ash" />
<logout logout-url="/logout" logout-success-url="/" />
<access-denied-handler ref="" error-page="/" />
<!-- authentication-failure-url="/main?errormessage=authentication.login.failed" -->
<session-management
session-authentication-strategy-ref="sls" />
<port-mappings>
<port-mapping http="8080" https="8443" />
</port-mappings>
</http>
<authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider> <!-- user-service-ref="userDetailService" -->
<user-service>
<user name="subash" authorities="ROLE_ADMIN" password="123456"/>
</user-service>
<!-- <password-encoder ref="passwordEncoder">
</password-encoder> -->
</authentication-provider>
</authentication-manager>
<beans:bean id="ash"
class="com.remittance.session.CustomSavedRequestAwareAuthenticationSuccessHandler">
</beans:bean>
<beans:bean id="failureHandler" class="com.remittance.session.CustomAuthenticationFailureHandler">
</beans:bean>
<beans:bean id="forbiddenEntryPoint"
class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" />
<beans:bean id="customSessionFilter" class="com.remittance.session.CustomSessionFilter">
<beans:constructor-arg ref="sessionRegistry" />
</beans:bean>
<beans:bean id="sls"
class="com.remittance.session.SessionLoggingStrategy">
<beans:constructor-arg ref="sas" />
<beans:constructor-arg ref="sessionLogApi" />
</beans:bean>
<beans:bean id="sas"
class="com.remittance.session.PersistingConcurrentSessionControlStrategy">
<beans:constructor-arg name="sessionRegistry"
ref="sessionRegistry" />
<beans:constructor-arg name="sessionApi" ref="sessionApi" />
<beans:property name="maximumSessions" value="-1" />
</beans:bean>
<beans:bean id="sessionRegistry"
class="com.remittance.session.PersistingSessionRegistry">
<beans:constructor-arg ref="sessionApi" />
</beans:bean>
<beans:bean id="userDetailService"
class="com.remittance.session.UserDetailsServiceImpl">
<beans:constructor-arg ref="userRepository" />
</beans:bean>
<beans:bean id="passwordEncoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
<beans:bean id="userTest" class="com.remittance.session.UserTest">
<beans:constructor-arg ref="userRepository" />
</beans:bean>
<!-- OAuth2 Security -->
<!-- Resource protected by oauth2 security -->
<!-- OAuth Client Details -->
<oauth2:client-details-service id="clientDetails">
<oauth2:client client-id="android5.5" secret="1234567890" authorized-grant-types="password,authorization_code,refresh_token,implicit,client_credentials"
authorities="ROLE_CLIENT,ROLE_TRUSTED_CLIENT" scope="read,write,trust"/>
<oauth2:client client-id="nokia3320" secret="0987654321" authorized-grant-types="password,authorization_code,refresh_token,implicit,client_credentials"
authorities="ROLE_CLIENT,ROLE_TRUSTED_CLIENT" scope="read,write,trust"/>
</oauth2:client-details-service>
<!-- This defined token store, we have used in memory token store for now but this can be changed to a user defined one -->
<beans:bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore"/>
<!-- Load User By User name -->
<beans:bean id="clientDetailsUserDetailsService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<beans:constructor-arg ref="clientDetails"/>
</beans:bean>
<!-- This is where we defined token based configurations, token validity and other things -->
<beans:bean id="tokenService" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<beans:property name="tokenStore" ref="tokenStore"/>
<beans:property name="accessTokenValiditySeconds" value="500"/>
<beans:property name="clientDetailsService" ref="clientDetails"/>
<beans:property name="supportRefreshToken" value="true"/>
</beans:bean>
<!-- It Determine whether a given client authentication request has been approved by user or not -->
<!-- ToeknStoreUserApprovalHandler : A user approval handler that remembers approval decisions by consulting existing tokens -->
<beans:bean id="userApprovalHandler" class="org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler">
<beans:property name="tokenStore" ref="tokenStore"/>
<beans:property name="requestFactory" ref="oauth2RequestFactory"/>
</beans:bean>
<!-- Server issuing access token to the client after successfully authenticating the resource owner and obtaining authorization -->
<oauth2:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenService"
user-approval-handler-ref="userApprovalHandler">
<!-- <oauth2:authorization-code/> -->
<!-- <oauth2:client-credentials/> -->
<!-- <oauth2:implicit/> -->
<oauth2:password/>
<!-- <oauth2:refresh-token/> -->
</oauth2:authorization-server>
<authentication-manager id="clientAuthenticationManager">
<authentication-provider user-service-ref="clientDetailsUserDetailsService"/>
</authentication-manager>
<!-- Include this if you need to authenticate client via request parameter -->
<beans:bean id="clientCredentialsTokenEndPointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<beans:property name="authenticationManager" ref="clientAuthenticationManager" />
</beans:bean>
<!-- Server hosting the protected resource ,capable of accepting and responding to protected resource request using access tokens -->
<oauth2:resource-server id="resourceServerFilter" resource-id="test" token-services-ref="tokenService"/>
<!-- Authentication Entry Point -->
<beans:bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<beans:property name="realmName" value="test" />
</beans:bean>
<beans:bean id="clientAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<beans:property name="realmName" value="test/client" />
<beans:property name="typeName" value="Basic" />
</beans:bean>
<!-- Access Denied Handler -->
<beans:bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>
<!-- This beans prepares oauth2Request using incoming request parameter -->
<beans:bean id="oauth2RequestFactory" class="org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory">
<beans:constructor-arg ref="clientDetails"/>
</beans:bean>
<!-- Access Decision Manager -->
<beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased" xmlns="http://www.springframework.org/schema/beans">
<beans:constructor-arg>
<beans:list>
<beans:bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
<beans:bean class="org.springframework.security.access.vote.RoleVoter" />
<beans:bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</beans:list>
</beans:constructor-arg>
</beans:bean>
I request for token using http://localhost:8060/oauth/token?grant_type=password&client_id=nokia3320&client_secret=0987654321&username=subash&password=123456and i got following response
我使用http://localhost:8060/oauth/token?grant_type=password&client_id=nokia3320&client_secret=0987654321&username=subash&password=123456请求令牌,我得到以下响应
{
"access_token": "9f5a89ce-a0d9-4d65-8e83-5d3b16d8c025",
"token_type": "bearer",
"refresh_token": "c2ac82ec-9f41-46dd-b7c2-4772c018505c",
"expires_in": 499,
"scope": "read trust write"
}
When i try to access resource using http://localhost:8060/Api/currencyListwith access token in authorizatioin error i got following response
当我尝试使用http://localhost:8060/Api/currencyList在授权错误中使用访问令牌访问资源时,我得到以下响应
{
"error": "unauthorized",
"error_description": "An Authentication object was not found in the
SecurityContext"
}
I want to protect the resource below using spring oauth2
我想使用spring oauth2保护下面的资源
@RequestMapping(value="/currencyList",method=RequestMethod.GET,produces={MediaType.APPLICATION_JSON_VALUE})
@ResponseBody
public List<CurrencyDTO> getCurrencyList(){
List<CurrencyDTO> currencyList=new ArrayList<CurrencyDTO>();
CurrencyDTO currency1 = new CurrencyDTO();
currency1.setCurrencyCode("NEP");
currency1.setCurrencyName("Rupees");
currency1.setId((long)1);
currency1.setSymbol("Rs");
CurrencyDTO currency2 = new CurrencyDTO();
currency2.setCurrencyCode("AM");
currency2.setCurrencyName("Dollar");
currency2.setId((long)2);
currency2.setSymbol("$");
currencyList.add(currency1);
currencyList.add(currency2);
return currencyList;
}
I got stuck in this problem for about 2 days.How could i resolve this problem?
我被这个问题困了大约 2 天。我该如何解决这个问题?
回答by Cataclysm
In my case, I added my api urls as public urls. My oauth protected REST-Service urls start with /resource/api/**
, but I added in my security configuration class as
就我而言,我将我的 api 网址添加为公共网址。我的 oauth 保护的 REST-Service url 以 开头/resource/api/**
,但我在我的安全配置类中添加了
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**","/js/**","/resource/**");
}
So, OAuth2AuthenticationProcessingFilter
did not invoke and I got exception as Authentication Object was not found in the SecurityContext
at my api server.
所以,OAuth2AuthenticationProcessingFilter
没有调用,我Authentication Object was not found in the SecurityContext
在我的 api 服务器上遇到了异常。
回答by San
On successful authentication, you have to add authentication object in security context as
成功认证后,您必须在安全上下文中添加认证对象作为
public void successfulAuthentication(HttpServletRequest request,HttpServletResponse response,
FilterChain chain, Authentication authentication) throws IOException, ServletException {
//your some custom code
// Add the authentication to the Security context
SecurityContextHolder.getContext().setAuthentication(authentication);
}
回答by subash048
The problem here is that both resource and authorization server don't share the common memory location for token.When i change InMemoryTokenStore to JdbcTokenStore my problem get solved.
这里的问题是资源和授权服务器不共享令牌的公共内存位置。当我将 InMemoryTokenStore 更改为 JdbcTokenStore 时,我的问题得到解决。
回答by Deepak Kumar
Please update your pom file spring boot parent release 1.4.2.RELEASE
请更新你的 pom 文件 spring boot parent release 1.4.2.RELEASE