Spring Security 4 + OAuth2 = 坏凭证
Posted
技术标签:
【中文标题】Spring Security 4 + OAuth2 = 坏凭证【英文标题】:Spring Security 4 + OAuth2 = Bad Credentials 【发布时间】:2016-09-12 13:34:47 【问题描述】:我正在使用 Spring Security + Oauth2 进行多个提议。场景是:有一个公共上下文、一个私有上下文和一个 REST 上下文(最后两个都经过身份验证)。
对于私有上下文 (/private/),未通过身份验证的用户应重定向到 /login,在进行身份验证之前,将重定向到 /private/index。对于 REST 上下文 (/rest/),用户应该拥有一个令牌,然后才能访问该区域。
记住这是一个 POC,代码非常基础。
spring-security.xml
<beans:beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xsi:schemaLocation="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
http://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2.xsd">
<sec:http pattern="/oauth/token" create-session="stateless"
authentication-manager-ref="clientAuthenticationManager"
use-expressions="true" xmlns="http://www.springframework.org/schema/security">
<sec:intercept-url pattern="/oauth/token" access="isAuthenticated()" />
<sec:anonymous enabled="false" />
<sec:http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<!-- include this only if you need to authenticate clients via request
parameters -->
<sec:custom-filter ref="clientCredentialsTokenEndpointFilter"
after="BASIC_AUTH_FILTER" />
<sec:access-denied-handler ref="oauthAccessDeniedHandler" />
</sec:http>
<!-- Spring Security Context -->
<sec:http auto-config="true" use-expressions="true"
xmlns="http://www.springframework.org/schema/security">
<sec:intercept-url pattern="/" access="permitAll" />
<sec:intercept-url pattern="/private/**" access="hasRole('ROLE_USER')" />
<sec:form-login authentication-failure-url="/login?error" />
<sec:logout logout-success-url="/login?logout" />
</sec:http>
<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="test" />
</bean>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="test/client" />
<property name="typeName" value="Basic" />
</bean>
<bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager" />
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
<constructor-arg>
<list>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
<bean
class="org.springframework.security.web.access.expression.WebExpressionVoter" />
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</list>
</constructor-arg>
</bean>
<sec:authentication-manager id="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<sec:authentication-provider
user-service-ref="clientDetailsUserService" />
</sec:authentication-manager>
<sec:authentication-manager alias="authenticationManager"
xmlns="http://www.springframework.org/schema/security">
<sec:authentication-provider>
<sec:user-service id="userDetailsService">
<sec:user name="admin" password="admin" authorities="ROLE_ADMIN, ROLE_USER" />
<sec:user name="user" password="user" authorities="ROLE_USER" />
</sec:user-service>
</sec:authentication-provider>
</sec:authentication-manager>
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails" />
</bean>
<!-- Used for the persistenceof tokens (currently an in memory implementation) -->
<bean id="tokenStore"
class="org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore" />
<!-- Used to create token and and every thing about them except for their
persistence that is reposibility of TokenStore (Given here is a default implementation) -->
<bean id="tokenServices"
class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="true" />
<property name="clientDetailsService" ref="clientDetails" />
</bean>
<bean id="userApprovalHandler"
class="org.springframework.security.oauth2.provider.approval.DefaultUserApprovalHandler">
</bean>
<!-- authorization-server aka AuthorizationServerTokenServices is an interface
that defines everything necessary for token management -->
<oauth:authorization-server
client-details-service-ref="clientDetails" token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler">
<oauth:authorization-code />
<oauth:implicit />
<oauth:refresh-token />
<oauth:client-credentials />
<oauth:password />
</oauth:authorization-server>
<oauth:resource-server id="resourceServerFilter"
resource-id="test" token-services-ref="tokenServices" />
<!-- ClientsDeailsService: Entry Point to clients database (given is in
memory implementation) -->
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="my-trusted-client"
authorized-grant-types="password,authorization_code,refresh_token,implicit"
authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT" scope="read,write,trust"
access-token-validity="60" />
<oauth:client client-id="my-trusted-client-with-secret"
authorized-grant-types="password,authorization_code,refresh_token,implicit"
secret="somesecret" authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT" />
<oauth:client client-id="my-client-with-secret"
authorized-grant-types="client_credentials" authorities="ROLE_CLIENT"
scope="read" secret="secret" />
<oauth:client client-id="my-less-trusted-client"
authorized-grant-types="authorization_code,implicit" authorities="ROLE_CLIENT" />
<oauth:client client-id="my-less-trusted-autoapprove-client"
authorized-grant-types="implicit" authorities="ROLE_CLIENT" />
<oauth:client client-id="my-client-with-registered-redirect"
authorized-grant-types="authorization_code,client_credentials"
authorities="ROLE_CLIENT" redirect-uri="http://anywhere?key=value"
scope="read,trust" />
<oauth:client client-id="my-untrusted-client-with-registered-redirect"
authorized-grant-types="authorization_code" authorities="ROLE_CLIENT"
redirect-uri="http://anywhere" scope="read" />
<oauth:client client-id="tonr" resource-ids="test"
authorized-grant-types="authorization_code,implicit" authorities="ROLE_CLIENT"
scope="read,write" secret="secret" />
<!--Self defined client -->
<oauth:client client-id="the_client"
authorized-grant-types="authorization_code,client_credentials"
authorities="ROLE_USER" scope="read,write,trust" secret="secret" />
</oauth:client-details-service>
<sec:global-method-security
pre-post-annotations="enabled" proxy-target-class="true"
xmlns="http://www.springframework.org/schema/security">
<!--you could also wire in the expression handler up at the layer of the
http filters. See https://jira.springsource.org/browse/SEC-1452 -->
<sec:expression-handler ref="oauthExpressionHandler" />
</sec:global-method-security>
<oauth:expression-handler id="oauthExpressionHandler" />
<oauth:web-expression-handler id="oauthWebExpressionHandler" />
【问题讨论】:
【参考方案1】:问题解决了。
如需进一步咨询,只需将“alias”一词更改为“id”,如下所示
<sec:authentication-manager alias="authenticationManager"
xmlns="http://www.springframework.org/schema/security">
正确:
<sec:authentication-manager id="authenticationManager"
xmlns="http://www.springframework.org/schema/security">
并且有效!
【讨论】:
以上是关于Spring Security 4 + OAuth2 = 坏凭证的主要内容,如果未能解决你的问题,请参考以下文章
Spring security 4.2.3,OAUTH 2,/oauth/token 端点,CORS 不工作
Spring Security 4 + OAuth2 = 坏凭证
针对授权标头的Spring Security OAuth2 CORS问题
Spring Security OAuth2分布式系统认证解决方案