我有一个情况:
步骤 1:获取访问令牌(grant_type=密码((A1(和刷新令牌。(RT1(
步骤 2:使用令牌 (A1( 访问资源 (R( - 成功
步骤 3:撤销资源 R 的用户访问角色。
步骤 4:获取访问令牌(grant_type=密码((A2(和刷新令牌。(RT2(
步骤 5:使用令牌 (A2( 访问的资源 (R( - 失败
直到这里一切都很好,现在出现了意想不到的部分。
步骤 6:使用 RT2 获取新的访问令牌 (grant_type=refresh_token(。出乎意料地使用此访问令牌,我能够访问资源 R。
在整个流程中,没有一个令牌过期。
我在这里看到两个问题:- 用户角色没有更新 grant_type=password 和 grant_type=refresh_token 上的刷新令牌。尽管访问令牌已更改(步骤 4(,但刷新令牌保持不变 RT1 == RT2。因此,RT 的任何进一步使用都会提供具有先前角色的访问令牌。
我如何告诉 spring (oauth2( 更新用户角色(对于新创建的令牌(,同时使用刷新令牌获取访问令牌,并使用新角色更新 RT(步骤4(,以解决此差异。
以下是授权服务器配置:
<?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"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService">
<bean class="com.dummy.mc.security.service.UserDetailsServiceImpl">
<property name="userRepository" ref="userRepository" />
<property name="grantedAuthorityRepository" ref="grantedAuthorityRepository" />
</bean>
</property>
<property name="passwordEncoder">
<bean class="com.dummy.mc.security.password.McpmPasswordEncoder">
<property name="encodeHashAsBase64" value="true" />
</bean>
</property>
<property name="saltSource">
<bean class="org.springframework.security.authentication.dao.ReflectionSaltSource">
<property name="userPropertyToUse" value="salt" />
</bean>
</property>
</bean>
<!--https://stackoverflow.com/questions/49761597/spring-oauth2-clientid-passed-in-as-username-for-password-grant-type-->
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore">
<constructor-arg ref="dataSource" />
</bean>
<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="clientDetailsService" />
<property name="reuseRefreshToken" value="false"/>
</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="clientDetailAuthenticationManager" />
</bean>
<!-- Authentication manager for client (not resource-owner) authentication required to
protect the token endpoint URL -->
<security:authentication-manager id="clientDetailAuthenticationManager">
<security:authentication-provider user-service-ref="clientDetailsUserService"/>
</security:authentication-manager>
<bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetailsService"/>
</bean>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="test/client" />
<property name="typeName" value="Basic" />
</bean>
<security:http pattern="/oauth/token" create-session="stateless" use-expressions="true" authentication-manager-ref="authenticationManager">
<security:intercept-url pattern="/oauth/token" access="isAuthenticated()" />
<security:anonymous enabled="false" />
<security:http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<!-- include this only if you need to authenticate clients via request
parameters -->
<security:custom-filter ref="clientCredentialsTokenEndpointFilter"
after="BASIC_AUTH_FILTER" />
<security:access-denied-handler ref="oauthAccessDeniedHandler" />
</security:http>
<authorization-server client-details-service-ref="clientDetailsService"
xmlns="http://www.springframework.org/schema/security/oauth2" token-services-ref="tokenServices" >
<authorization-code />
<implicit />
<refresh-token />
<client-credentials />
<password authentication-manager-ref="authenticationManager" />
</authorization-server>
<!-- <oauth:resource-server id="resourceFilter" token-services-ref="tokenServices" authentication-manager-ref="authenticationManager" />
-->
<security:authentication-manager id="authenticationManager">
<security:authentication-provider ref="daoAuthenticationProvider">
</security:authentication-provider>
</security:authentication-manager>
<oauth:client-details-service id="clientDetailsService">
<oauth:client client-id="core-api" secret="secret"
authorized-grant-types="password,client_credentials,refresh_token" scope="read"
resource-ids="api-core" access-token-validity="36000"
authorities="ROLE_CLIENT,ROLE_TRUSTED_CLIENT" />
</oauth:client-details-service>
</beans>
资源服务器配置:
<mvc:default-servlet-handler />
<mvc:annotation-driven/>
<security:global-method-security pre-post-annotations="enabled"/>
<!-- TODO: make an access denied view that tells me something useful -->
<security:http use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint">
<security:intercept-url pattern="/**" access="isFullyAuthenticated() and hasRole('api.core')" />
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<security:access-denied-handler ref="oauthAccessDeniedHandler" />
<security:anonymous />
</security:http>
<!-- It's just a "feature" of the Spring Security that an authentication manager is mandatory.
so install an empty one because it isn't used at run time -->
<security:authentication-manager/>
<oauth:resource-server id="resourceServerFilter" token-services-ref="tokenServices" resource-id="api-core"/>
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices" >
<property name="tokenStore" ref="tokenStore" />
</bean>
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore">
<constructor-arg ref="dataSource" />
</bean>
<bean id="oauthAuthenticationEntryPoint" 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" />
当访问令牌需要时,将加载颁发机构。 使用 jdbc 存储,权限将保存到OAUTH_ACCESS_TOKEN表的"身份验证"列中。
当需要刷新令牌时,将从数据库加载权限。
如果在需要访问令牌后更改了权限,则必须实现自定义令牌存储。
看看org.springframework.security.oauth2.provider.token.store.JdbcTokenStore,并从中扩展。