小星星啊 2016-09-06 08:47 采纳率: 0%
浏览 6693

spring security oauth2 的一个问题 求大神指点

在oauth2根据授权码获取accsess token时,通关Debug发现在TokenEndpoint类下的getAccessToken方法内会根据principal去数据库获取client_id,但principal内存储的是当前用户的信息,然后就会报错:Given client ID does not match authenticated client

求大神解答怎么破.

security.xml文件如下:

 <?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:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:oauth2="http://www.springframework.org/schema/security/oauth2"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                        http://www.springframework.org/schema/security/oauth2
                        http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
                        http://www.springframework.org/schema/security
                        http://www.springframework.org/schema/security/spring-security-3.2.xsd">


    <!-- 指定不需要权限过滤的路径 -->
    <http pattern="/login.jsp" security="none" />

    <http pattern="/aouth/token" create-session="stateless"
        authentication-manager-ref="oauth2AuthenticationManager"
        entry-point-ref="oauth2AuthenticationEntryPoint">

        <!-- 设置拦截地址和规则 -->
        <intercept-url pattern="/aouth/token" access="IS_AUTHENTICATED_FULLY" />
        <!-- 非匿名 -->
        <anonymous enabled="false" />

        <http-basic entry-point-ref="oauth2AuthenticationEntryPoint" />
        <!-- 设置过滤链 -->
        <custom-filter ref="clientCredentialsTokenEndpointFilter"
            before="BASIC_AUTH_FILTER" />
        <!-- 拒绝访问处理 -->
        <access-denied-handler ref="oauthAccessDeniedHandler" />
    </http>
    <!--一个自定义的filter,必须包含authenticationManager,accessDecisionManager,securityMetadataSource三个属性, 
        我们的所有控制将在这三个类中实现 -->
    <beans:bean id="myFilter"
        class="com.yichi.mvcm.filter.MyFilterSecurityInterceptor">
        <beans:property name="authenticationManager" ref="authenticationManager" />
        <beans:property name="accessDecisionManager" ref="myAccessDecisionManagerBean" />
        <beans:property name="securityMetadataSource"
            ref="myInvocationSecurityMetadataSource" />
    </beans:bean>
    <!-- 认证客户端的manager -->
    <authentication-manager id="oauth2AuthenticationManager">
        <authentication-provider user-service-ref="oauth2ClientDetailsUserService" />
    </authentication-manager>

    <!-- spring security提供的用户登录验证 ,alias的值对应上面的ref="authenticationManager" -->
    <authentication-manager alias="authenticationManager">
        <!--userDetailServiceImpl 获取登录的用户、用户权限 -->
        <authentication-provider user-service-ref="myUserDetailService" />
        <!-- 缓存 -->
        <!-- <authentication-provider user-service-ref="cachingUserDetailsService" 
            /> -->
    </authentication-manager>
    <!-- 缓存 -->
    <!-- <beans:bean id="cachingUserDetailsService" class="org.springframework.security.config.authentication.CachingUserDetailsService"> 
        <beans:constructor-arg ref="myUserDetailService" /> 缓存UserDetails的UserCache 
        <beans:property name="userCache" ref="userCache"/> </beans:bean> <beans:bean 
        id="userCache" class="org.springframework.security.core.userdetails.cache.EhCacheBasedUserCache"> 
        用于真正缓存的Ehcache对象 <beans:property name="cache" ref="ehcache4UserDetails"></beans:property> 
        </beans:bean> <beans:bean id="ehcache4UserDetails" class="org.springframework.cache.ehcache.EhCacheFactoryBean" 
        /> -->

    <!--在这个类中,你就可以从数据库中读入用户的密码,角色信息,是否锁定,账号是否过期等 -->
    <beans:bean id="myUserDetailService" class="com.yichi.mvcm.filter.MyUserDetailService">
        <!-- 配置成员变量 -->
        <beans:property name="sysUserService" ref="sysUserService" />
    </beans:bean>
    <!--访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源 -->
    <beans:bean id="myAccessDecisionManagerBean"
        class="com.yichi.mvcm.filter.MyAccessDecisionManager">
    </beans:bean>
    <beans:bean id="sysResService" class="com.yichi.mvcm.service.sys.SysResService"></beans:bean>
    <!--资源源数据定义,将所有的资源和权限对应关系建立起来,即定义某一资源可以被哪些角色访问 -->
    <beans:bean id="myInvocationSecurityMetadataSource"
        class="com.yichi.mvcm.filter.MyInvocationSecurityMetadataSource">
        <!-- 配置成员变量 -->
        <beans:constructor-arg>
            <beans:ref bean="sysResService" />
        </beans:constructor-arg>
    </beans:bean>

    <!-- 配置client客户端信息 -->
    <authentication-manager id="clientAuthenticationManager">

        <authentication-provider user-service-ref="oauth2ClientDetailsUserService" />
    </authentication-manager>
    <beans:bean id="oauth2ClientDetailsUserService"
        class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
        <beans:constructor-arg ref="clientDetailsService" />
    </beans:bean>


    <!-- 数据库读取客户端信息 -->
     <beans:bean id="clientDetailsService" class="com.yichi.mvcm.filter.CustomJdbcClientDetailsService"> 
        <beans:constructor-arg index="0" ref="dataSource" /> </beans:bean> 

    <!-- 资源filter配置 -->
    <oauth2:resource-server id="picResourceServer"
        resource-id="pic-resource" token-services-ref="tokenServices" />

    <!-- 配token service用于生成访问令牌token -->
    <beans:bean id="tokenServices"
        class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
        <beans:property name="tokenStore" ref="tokenStore" />
        <!-- 是否生成更新令牌 默认为false -->
        <beans:property name="supportRefreshToken" value="true" />
        <beans:property name="clientDetailsService" ref="clientDetailsService" />
    </beans:bean>

    <!-- token仓库 可以选择存储在内存或者数据库 -->
    <!-- <beans:bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore"> 
        </beans:bean> -->
    <beans:bean id="tokenStore"
        class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore">
        <beans:constructor-arg index="0" ref="dataSource" />
    </beans:bean>

    <!-- 资源 -->
    <http pattern="/mvcm/**" create-session="never"
        entry-point-ref="oauth2AuthenticationEntryPoint"
        access-decision-manager-ref="oauth2AccessDecisionManager">
        <anonymous enabled="false" />
        <intercept-url pattern="/mvcm/**" access="ROLE_index,SCOPE_READ" />
        <custom-filter ref="picResourceServer" before="PRE_AUTH_FILTER" />
        <access-denied-handler ref="oauthAccessDeniedHandler" />
    </http>

    <beans:bean id="oauth2AuthenticationEntryPoint"
        class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint" />

    <beans:bean id="oauthAccessDeniedHandler"
        class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />

    <beans:bean id="oauth2AccessDecisionManager"
        class="org.springframework.security.access.vote.UnanimousBased">
        <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>
    <!-- user-approval-page:用户第三方登录认证以后的授权确认页面 error-page : 客户端申请授权的数据与服务端的不相同时跳转的页面 -->
    <oauth2:authorization-server 
        client-details-service-ref="clientDetailsService" token-services-ref="tokenServices"
        user-approval-handler-ref="oauthUserApprovalHandler"
        user-approval-page="oauth_approval" error-page="oauth_error">
        <oauth2:authorization-code 
            authorization-code-services-ref="authorizationCodeServices" />
        <oauth2:implicit />
        <oauth2:refresh-token />
        <oauth2:client-credentials />
        <oauth2:password />
    </oauth2:authorization-server>

    <!-- 授权码存储到数据库 -->
    <beans:bean id="authorizationCodeServices"
        class="org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices">
        <beans:constructor-arg index="0" ref="dataSource" />
    </beans:bean>


    <beans:bean id="oauthUserApprovalHandler"
        class="org.springframework.security.oauth2.provider.approval.DefaultUserApprovalHandler" />


    <!--  <beans:bean id="clientCredentialsTokenEndpointFilter"
        class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
        <beans:property name="authenticationManager" ref="clientAuthenticationManager" />
    </beans:bean>  -->
     <beans:bean id="clientCredentialsTokenEndpointFilter"
        class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
        <beans:property name="authenticationManager" ref="clientAuthenticationManager" />
    </beans:bean> 

    <http auto-config="true" use-expressions="true">
        <!-- 没有权限时跳转的页面 -->
        <access-denied-handler error-page="/accessDenied.jsp" />
        <!-- 使用自定义的登录页面 login_page:指定登录页面 authentication-failure-url:登录失败跳转到/login.jsp 
            login-processing-url进行认证拦截的请求路径 username-parameter和 password-parameter指定属性name字段 
            default-target-url认证成功默认跳转页面 -->
        <form-login login-page="/login.jsp"
            authentication-failure-url="/login.jsp?error=1" login-processing-url="/springSecurity"
            username-parameter="account" password-parameter="password"
            default-target-url="/index.jsp" />

            <intercept-url pattern="/oauth/**" access="hasRole('ROLE_userOrg')" />
        <!-- 设置单用户登录 -->
        <session-management>
            <!-- max-sessions表示最多允许多少次重复登录。如果没有配置error-if-maximum-exceeded, 那么用户账号的第二次登录会使第一次登录失效,而配置了的话,那么第二次登录会被阻止。 
                通常的做法是阻止第二次登录。 -->
            <concurrency-control max-sessions="1"
                error-if-maximum-exceeded="false" />
        </session-management>

        <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR" />

        <!-- 检测失效的sessionId,session超时时,定位到另外一个URL -->
        <session-management invalid-session-url="/login.jsp" />

        <logout invalidate-session="true" logout-success-url="/"
            logout-url="/logout" />

    </http>
</beans:beans>

  • 写回答

1条回答

  • zealVampire 2016-09-13 02:47
    关注

    You should provice more infomation or exception, make sure you post(not http get) the client id and password,
    so that client_id wn't be empty, and make sure your ClientDetailService get load the client by id,
    keep debugging and you will find the error.

    TokenEndpoint.java

        @RequestMapping(value = "/oauth/token", method=RequestMethod.POST)
        public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam
        Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
    
            if (!(principal instanceof Authentication)) {
                throw new InsufficientAuthenticationException(
                        "There is no client authentication. Try adding an appropriate authentication filter.");
            }
    
            String clientId = getClientId(principal);
            ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId);
    
            TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);
    
            if (clientId != null && !clientId.equals("")) {
                // Only validate the client details if a client authenticated during this
                // request.
                if (!clientId.equals(tokenRequest.getClientId())) {
                    // double check to make sure that the client ID in the token request is the same as that in the
                    // authenticated client
                    throw new InvalidClientException("Given client ID does not match authenticated client");
                }
            } 
    

    DefaultOAuth2RequestFactory.java

        public TokenRequest createTokenRequest(Map<String, String> requestParameters, ClientDetails authenticatedClient) {
    
            String clientId = requestParameters.get(OAuth2Utils.CLIENT_ID);
            if (clientId == null) {
                // if the clientId wasn't passed in in the map, we add pull it from the authenticated client object
                clientId = authenticatedClient.getClientId();
            }
            else {
                // otherwise, make sure that they match
                if (!clientId.equals(authenticatedClient.getClientId())) {
                    throw new InvalidClientException("Given client ID does not match authenticated client");
                }
            }
            String grantType = requestParameters.get(OAuth2Utils.GRANT_TYPE);
    
            Set<String> scopes = extractScopes(requestParameters, clientId);
            TokenRequest tokenRequest = new TokenRequest(requestParameters, clientId, scopes, grantType);
    
            return tokenRequest;
        }
    
    评论

报告相同问题?

悬赏问题

  • ¥20 iqoo11 如何下载安装工程模式
  • ¥15 本题的答案是不是有问题
  • ¥15 关于#r语言#的问题:(svydesign)为什么在一个大的数据集中抽取了一个小数据集
  • ¥15 C++使用Gunplot
  • ¥15 这个电路是如何实现路灯控制器的,原理是什么,怎么求解灯亮起后熄灭的时间如图?
  • ¥15 matlab数字图像处理频率域滤波
  • ¥15 在abaqus做了二维正交切削模型,给刀具添加了超声振动条件后输出切削力为什么比普通切削增大这么多
  • ¥15 ELGamal和paillier计算效率谁快?
  • ¥15 蓝桥杯单片机第十三届第一场,整点继电器吸合,5s后断开出现了问题
  • ¥15 file converter 转换格式失败 报错 Error marking filters as finished,如何解决?