从 grant_type=password 和 grant_type=refresh_token 获取的访问令牌中的用户角色(权限)存在差异 [英] Discrepancy in the user roles(authorities) in the access token obtained from grant_type=password and grant_type=refresh_token

查看:88
本文介绍了从 grant_type=password 和 grant_type=refresh_token 获取的访问令牌中的用户角色(权限)存在差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个情况:

第 1 步:获取访问令牌(grant_type=password)(A1)和刷新令牌.(RT1)

Step 1: Obtained access token (grant_type=password) (A1) and also a refresh token.(RT1)

第 2 步:使用令牌 (A1) 访问资源 (R) - 成功

Step 2: Accessed resource (R) using the token (A1) - Success

第 3 步:撤销资源 R 的用户访问权限.

Step 3:Revoked user access role for Resource R.

第 4 步:获取访问令牌(grant_type=password)(A2)和刷新令牌.(RT2)

Step 4: Obtained access token (grant_type=password) (A2) and also a refresh token.(RT2)

第 5 步:使用令牌 (A2) 访问资源 (R) - 失败

Step 5: Accessed resource (R) using the token (A2) - Failed

到这里一切正常.现在是意想不到的部分.

till here all fine.now comes the unexpected part.

第 6 步:使用 RT2 获取新的访问令牌 (grant_type=refresh_token).意外地使用这个访问令牌,我能够访问资源 R.

Step 6: Obtained new access token (grant_type=refresh_token) using RT2. Unexpectedly using this access token i was able to access resource R.

在整个流程中,没有任何令牌过期.

During this whole flow none of the token was expired one.

我在这里看到两个问题:- 用户角色未针对 grant_type=password 和 grant_type=refresh_token 上的刷新令牌进行更新.尽管访问令牌已更改(步骤 4)但刷新令牌保持不变 RT1 == RT2.因此,任何进一步使用 RT 都会提供具有先前角色的访问令牌.

I see two issues here:- User roles aren't getting updated for refresh token on grant_type=password and for grant_type=refresh_token. Although access token has changed (Step 4) but refresh token remains same RT1 == RT2. hence any further usage of RT gives access token with previous roles.

我如何告诉 spring (oauth2) 更新用户角色(对于新创建的令牌),同时使用刷新令牌获取访问令牌以及使用新角色更新 RT(步骤 4),以解决此差异.

How do i tell spring (oauth2) to update user roles (for the newly created token's) while obtaining the access token using refresh token and also while updating RT with new roles (step4), to resolve this discrepancy.

以下是授权服务器配置:

Below is the Authorization server configuration:

 <?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 store,权限保存到OAUTH_ACCESS_TOKEN表,AUTHENTICATION列.

Authorities are loaded when access token its required. Using jdbc store, authorities are saved to OAUTH_ACCESS_TOKEN table, AUTHENTICATION column.

当需要刷新令牌时,从数据库加载权限.

When refresh token its required, authorities are loaded from database.

如果在需要访问令牌后权限发生变化,您将必须实现自定义令牌存储.

If authorities changed after access token was required, you will have to implement custom token store.

查看 org.springframework.security.oauth2.provider.token.store.JdbcTokenStore,并从中扩展.

Take a look to org.springframework.security.oauth2.provider.token.store.JdbcTokenStore, and extend from it.

这篇关于从 grant_type=password 和 grant_type=refresh_token 获取的访问令牌中的用户角色(权限)存在差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆