【问题标题】:How to change spring security oauth2 default token endpoint?如何更改 spring security oauth2 默认令牌端点?
【发布时间】:2014-04-08 23:58:54
【问题描述】:

我们有基于 spring security oauth2 的应用程序。每件事都运行良好。但我未能将默认令牌端点从“/oauth/token”更改为“/external/oauth/token”。

我的 spring-servlet.xml

<http pattern="/external/oauth/token" create-session="stateless" 
       authentication-manager-ref="clientAuthenticationManager"
       use-expressions="true" xmlns="http://www.springframework.org/schema/security">
      <intercept-url pattern="/external/oauth/token" access="isFullyAuthenticated()" />
      <anonymous enabled="false" />
      <http-basic entry-point-ref="clientAuthenticationEntryPoint" />
      <!-- include this only if you need to authenticate clients via request parameters -->
      <custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" />
      <access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>

<oauth:authorization-server client-details-service-ref="clientDetails" 
        token-services-ref="tokenServices" 
        user-approval-handler-ref="userApprovalHandler" token-endpoint-url="/external/oauth/token">
        <oauth:authorization-code />
        <oauth:implicit />
        <oauth:refresh-token />
        <oauth:client-credentials />
        <oauth:password />
</oauth:authorization-server>

但是当我访问这个端点时的结果是

{
    error: "unauthorized"
    error_description: "An Authentication object was not found in the SecurityContext"
}

我错过了什么吗?请提出建议。

【问题讨论】:

    标签: spring-security-oauth2


    【解决方案1】:

    使用spring-security-oauth2 2.0.5.RELEASE或以上版本

    在基于 java 的配置中,经过测试并且工作正常,它以某种方式覆盖了 TokenEndpoint 类的 RequestMapping 值。

    @Configuration
    @EnableAuthorizationServer
    protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {      
    
            @Override
            public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
                endpoints
                    .pathMapping("/oauth/token", "<your custom endpoint>")
            }
    }
    

    【讨论】:

    • 嗨@Emilien Brigand 我试过这个来改变endpoints.pathMapping("/oauth/authorize", "/external/oauth/authorize");但它不会转到我在自定义控制器中定义的自定义操作映射。您能提出解决方案吗?
    • 以防万一,您是否放置了端点的路径而不是“/external/oauth/authorize”?
    • 您好@Emilien Brigand 感谢您的回复。你能告诉我你说的是哪条端点路径吗?
    • 我说的是你的自定义控制器,一个控制器定义了一个 REST 端点,所以你只需要放它的 URL
    • 嗨@Emilien Brigand 感谢您的回复。你的意思是说如果我的控制器端点是localhost:8080/api//external/oauth/token那么我需要这样给映射:endpoints .pathMapping("/oauth/token", "/api/external/oauth/token") 这个映射,你的意思是说?
    【解决方案2】:

    为此苦苦挣扎了几天,但现在可以在最新的 Spring Oauth2 1.0.5.RELEASE 上运行。我不是 100% 确定我的解决方案是最经典的(尤其是第 4 步),但它有效,我能够继续前进。

    在我的例子中,我想从 URL 中删除 /oauth 前缀,最终只剩下 /token/authorize。我的解决方案主要是 xml 配置,有两个技巧可以覆盖端点请求映射。

    1 - 在应用上下文 xml 中,将 authorization-endpoint-urltoken-endpoint-url 属性添加到您的 &lt;oauth:authorization-server&gt; 元素。

    我的:

    <oauth:authorization-server client-details-service-ref="clientDetailsService" token-services-ref="tokenServices" user-approval-handler-ref="userApprovalHandler" authorization-endpoint-url="/authorize" token-endpoint-url="/token">
    

    2 - 在应用上下文 xml 中,相应地调整安全端点。应该有两个,分别管理令牌和身份验证 URL 的安全性。需要更新&lt;http&gt;&lt;intercept-url&gt; 标签上的pattern prop。

    我的:

    <http pattern="/token/**" create-session="stateless" authentication-manager-ref="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
        <intercept-url pattern="/token/**" access="IS_AUTHENTICATED_FULLY" />
    
    ...
    
    <http pattern="/authorize/**" access-denied-page="/login.jsp?authorization_error=true" disable-url-rewriting="true" xmlns="http://www.springframework.org/schema/security">
        <intercept-url pattern="/authorize/**" access="IS_AUTHENTICATED_FULLY" />
    

    3 - (如果您选择使用可选的 clientCreds 过滤器。)在应用上下文 xml 中,您应该已经将 clientCredentialsTokenEndpointFilter bean 作为 &lt;custom-filter&gt; within yourelement. So, within the filter's bean, add afilterProcessesUrl` 属性连接到了。

    我的:

    <bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
        <property name="authenticationManager" ref="clientAuthenticationManager" />
        <property name="filterProcessesUrl" value="/token" />
    </bean>
    

    4 - 最后一步是覆盖实际内部端点控制器的请求映射 url。 spring oauth2 库带有两个类:AuthorizationEndpointTokenEndpoint。每个都使用@RequestMapping 类型注释来绑定url(就像我们对项目的应用程序控制器所做的那样)。对我来说,除了(可悲地)在我的 src 文件夹中重新创建 spring 类包,将 AuthorizationEndpoint 和 TokenEndpoint 类逐字复制到所述文件夹中之外,尝试以任何方式覆盖请求映射的值是一项艰巨的工作,并编辑内联 @RequestMapping 注释值。

    无论如何,这就是诀窍。希望听到一种更优雅的方式来覆盖端点控制器请求映射值。

    谢谢。

    最终的工作应用上下文:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:sec="http://www.springframework.org/schema/security" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
    
      xsi:schemaLocation="
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
        http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd
      "
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    >
    
      <!-- Declare OAuth2 services white-list. (This is the top of the config.) -->
      <oauth:authorization-server client-details-service-ref="clientDetailsService" token-services-ref="tokenServices" user-approval-handler-ref="userApprovalHandler" authorization-endpoint-url="/authorize" token-endpoint-url="/token">
        <oauth:authorization-code />
        <oauth:implicit />
        <oauth:refresh-token />
        <oauth:client-credentials />
        <!-- <oauth:password /> -->
      </oauth:authorization-server>
      <bean id="userApprovalHandler" class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler">
        <!-- This bean bridges client auth service and user tokens... kind of an out of place requirement. -->
        <property name="tokenServices" ref="tokenServices" />
      </bean>
    
      <!-- This starts the far back-end config for client token management. -->
      <sec:authentication-manager id="clientAuthenticationManager">
        <sec:authentication-provider user-service-ref="clientDetailsUserService" />
      </sec:authentication-manager>
      <bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
        <constructor-arg ref="clientDetailsService" />
      </bean>
      <bean id="clientDetailsService" class="com.mycompany.oauth.spring.security.oauth2.IntegratedOauth2ClientDetailsService">
        <!-- This bean is what wires OAuth2 into the persistence stack for client details stored in the oauth_client table. -->
      </bean>
    
    
      <!-- OAuth is layered on to spring security which is centered around users which requires a user auth manager.  -->
      <authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">
        <authentication-provider ref="daoAuthenticationProvider" />
      </authentication-manager>
      <bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
        <property name="userDetailsService" ref="userDetailsService" />
      </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" />
      </bean>
      <bean id="tokenStore" class="com.mycompany.oauth.spring.security.oauth2.IntegratedOAuth2TokenStore">
        <!-- This bean is what wires OAuth2 tokens into my company's application stack. -->
        <constructor-arg ref="dataSource" />
      </bean>
    
      <!-- **************************************************************************************** -->
      <!-- Finally, sew OAuth into spring security with some http tags... -->
      <!-- **************************************************************************************** -->
    
      <!-- The OAuth2 endpoint for direct token requests (i.e. for client_credentials flow). -->
      <http pattern="/token/**" create-session="stateless" authentication-manager-ref="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
        <intercept-url pattern="/token/**" access="IS_AUTHENTICATED_FULLY" />
        <anonymous enabled="false" />
        <http-basic entry-point-ref="clientAuthenticationEntryPoint" />
        <custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />
        <access-denied-handler ref="oauthAccessDeniedHandler" />
      </http>
      <bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
        <property name="authenticationManager" ref="clientAuthenticationManager" />
        <property name="filterProcessesUrl" value="/token" />
      </bean>
      <bean id="clientAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
        <property name="realmName" value="myrealm" />
      </bean>
      <bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
    
      <!-- The OAuth2 endpoint for user-approved authorization (i.e. for "authorization" flow involving user login/approve). -->
      <http pattern="/authorize/**" access-denied-page="/login.jsp?authorization_error=true" disable-url-rewriting="true" xmlns="http://www.springframework.org/schema/security">
        <intercept-url pattern="/authorize/**" access="IS_AUTHENTICATED_FULLY" />
        <form-login authentication-failure-url="/login.jsp?authentication_error=true" default-target-url="http://www.mycompany.com/" login-page="/login.jsp" login-processing-url="/login.do" />
        <http-basic />
        <anonymous />
      </http>
    
    </beans>
    

    【讨论】:

    • 请告诉我,clientAuthenticationEntryPoint 中的realmName 是什么。我也面临同样的错误,但没有自定义默认令牌 url。我正在为 Oauth 使用 spring-rest 服务。
    【解决方案3】:

    要自定义令牌端点 URL,请执行以下步骤。

    1) 编写您自己的类来扩展 ClientCredentialsTokenEndpointFilter 类并使用“/external/oauth/token”值调用 ClientCredentialsTokenEndpointFilter 类构造函数。

    super("/external/oauth/token");
    

    2) 在安全配置中插入新的自定义过滤器。

    替换

    <custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" />
    

    <custom-filter ref="your customize filter" after="BASIC_AUTH_FILTER" />
    

    3) 为新映射 (/external/oauth/token) 创建您自己的类并扩展 tokenendpoint。

    4) 将 http & intercept-url 元素的模式属性值更改为“/external/oauth/token”

    【讨论】:

    • 嗨 Anurag,我已经添加了所有这些行,并将结束指针引用提供给 标记。但是在服务器启动时,它会抛出异常“java.lang.IllegalArgumentException:必须指定 authenticationManager”。还有什么需要在这里做的吗?..谢谢
    • 您需要在您的 clientCredentialsTokenEndpoint 过滤器中设置 authenticationManager bean
    【解决方案4】:

    你做的比它应该做的更难,它实际上非常简单! (请注意,我使用“oauth2:”而不是“oauth:”作为 XML 标记)

    1. 转到您的 security-context.xml

    2. 在上述文件中找到“oauth2:authorization-server”。

      <oauth2:authorization-server
                      client-details-service-ref="someService"
                      request-validator-ref="someScopeRequestValidator"
                      token-services-ref="someTokenServices" >
      
    3. 只需添加token-endpoint-url="/oauth/whatever_you_like"

      <oauth2:authorization-server
                      client-details-service-ref="someService"
                      request-validator-ref="someScopeRequestValidator"
                      token-services-ref="someTokenServices" 
      **token-endpoint-url="/oauth/whatever_you_like"** >
      

    【讨论】:

    • 我正在尝试更改令牌端点 url,正如您对“/api/v1/oauth/token”所说的那样,但它给出了错误 -An Authentication object was not found in the SecurityContext。我错过了什么吗?
    • 这个解决方案帮助我通过 xml 配置将自定义 OAuth2RequestValidator 注入到 TokenEndpoint。
    猜你喜欢
    • 2015-08-26
    • 2020-04-19
    • 1970-01-01
    • 2020-07-20
    • 2015-01-01
    • 2019-03-03
    • 2016-08-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多