简体   繁体   English

Spring Security Oauth - 发送令牌请求时所需的基本访问身份验证

[英]Spring Security Oauth - Basic access authentication needed when sending token request

I've got one problem with Spring Security OAuth 2.0. 我对Spring Security OAuth 2.0有一个问题。

There is basic configuration of spring-security, taken from sample: 弹簧安全的基本配置取自样本:

<http pattern="/oauth/token" create-session="stateless"
    authentication-manager-ref="clientAuthenticationManager"
    xmlns="http://www.springframework.org/schema/security">
    <intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
    <anonymous enabled="false" />
    <http-basic entry-point-ref="clientAuthenticationEntryPoint" />
    <custom-filter ref="clientCredentialsTokenEndpointFilter"
        after="BASIC_AUTH_FILTER" />
    <access-denied-handler ref="oauthAccessDeniedHandler" />
</http>

<http pattern="/path/**" create-session="never"
    entry-point-ref="oauthAuthenticationEntryPoint"
    access-decision-manager-ref="accessDecisionManager"
    xmlns="http://www.springframework.org/schema/security">
    <anonymous enabled="false" />
    <intercept-url pattern="/path/*" access="ROLE_USER" />
    <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
    <access-denied-handler ref="oauthAccessDeniedHandler" />
</http>

<bean id="oauthAuthenticationEntryPoint"
    class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
    <property name="realmName" value="path" />
</bean>

<bean id="clientAuthenticationEntryPoint"
    class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
    <property name="realmName" value="path/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"
    xmlns="http://www.springframework.org/schema/beans">
    <constructor-arg>
        <list>
            <bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
            <bean class="org.springframework.security.access.vote.RoleVoter" />
            <bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
        </list>
    </constructor-arg>
</bean>

<bean id="oauthAuthenticationProvider" class="my.package.OAuthAuthenticationProvider" xmlns="http://www.springframework.org/schema/beans" />

<authentication-manager id="clientAuthenticationManager"
    xmlns="http://www.springframework.org/schema/security">
    <authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>

<authentication-manager alias="authenticationManager"
    xmlns="http://www.springframework.org/schema/security">
    <authentication-provider ref="oauthAuthenticationProvider" />
</authentication-manager>

<bean id="clientDetailsUserService"
    class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
    <constructor-arg ref="clientDetails" />
</bean>

<bean id="tokenStore"
    class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />

<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.TokenServicesUserApprovalHandler">
    <property name="tokenServices" ref="tokenServices" />
</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">
    <!-- 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 client-id="my-trusted-client-with-secret"
        authorized-grant-types="password,authorization_code,refresh_token,implicit"
        secret="somesecret" authorities="ROLE_USER" />

</oauth:client-details-service>

<sec:global-method-security
    pre-post-annotations="enabled" proxy-target-class="true">
    <sec:expression-handler ref="oauthExpressionHandler" />
</sec:global-method-security>

<oauth:expression-handler id="oauthExpressionHandler" />

<oauth:web-expression-handler id="oauthWebExpressionHandler" />

It works, when in my web.xml file looks like this: 它工作,当我在我的web.xml文件中看起来像这样:

...
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring-security.xml</param-value>
</context-param>
...
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
...
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
...
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
...
<servlet>
    <servlet-name>Dispatcher Servlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
...
<servlet-mapping>
    <servlet-name>Dispatcher Servlet</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping> 

But in this case, the "old part" of system doesn't work. 但在这种情况下,系统的“旧部分”不起作用。 So I have to change Dispatcher Servlet mapping: 所以我必须更改Dispatcher Servlet映射:

<servlet-mapping>
    <servlet-name>Dispatcher Servlet</servlet-name>
    <url-pattern>/somepath/*</url-pattern>
</servlet-mapping> 

Now the old part works, but not Oauth Spring security. 现在旧的部分工作,但不是Oauth Spring安全。 I've tried with two url-patterns: 我试过两个网址模式:

<servlet-mapping>
    <servlet-name>Dispatcher Servlet</servlet-name>
    <url-pattern>/somepath/*</url-pattern>
    <url-pattern>/*</url-pattern>
</servlet-mapping> 

Then oauth works, old part doesn't. 然后oauth工作,老部分没有。

I did one more try and changed: 我做了一次尝试并改变了:

<http pattern="/somepath/oauth/token" create-session="stateless"
    authentication-manager-ref="clientAuthenticationManager"
    xmlns="http://www.springframework.org/schema/security">
    <intercept-url pattern="/somepath/oauth/token" access="IS_AUTHENTICATED_FULLY" />
    <anonymous enabled="false" />
    <http-basic entry-point-ref="clientAuthenticationEntryPoint" />
    <custom-filter ref="clientCredentialsTokenEndpointFilter"
        after="BASIC_AUTH_FILTER" />
    <access-denied-handler ref="oauthAccessDeniedHandler" />
</http>

And now it works like this: 现在它的工作原理如下:

  1. I'm accessing address (which worked before): 我正在访问地址(之前有效):

    https://localhost.server:8443/system/somepath/oauth/token?grant_type=password&client_id=my-trusted-client-with-secret&client_secret=somesecret&username=user&password=pass HTTPS://localhost.server:8443 /系统/ somepath /的OAuth /令牌grant_type =密码&CLIENT_ID =我的信任,客户与秘密&client_secret = somesecret与用户名=用户密码=通

  2. Web browser asks for login and password (Basic access authentication). Web浏览器要求登录和密码(基本访问身份验证)。

  3. I need to enter client-id in login field and secret in password field. 我需要在登录字段中输入client-id,在密码字段中输入secret。

  4. Request to oauth is generated and then authentication method in my.package.OAuthAuthenticationProvider is called. 生成对oauth的请求,然后调用my.package.OAuthAuthenticationProvider中的身份验证方法。

What should I change to avoid this Basic auth prompt? 我应该更改什么以避免此基本身份验证提示?

Your problems with the servlet and filter mappings stem from the fact that Spring OAuth needs a DispatcherServlet for its OAuth related endpoints. 您对servlet和过滤器映射的问题源于Spring OAuth需要一个DispatcherServlet用于其OAuth相关端点。 I recommend you put those in the default servlet mapping (/), but it's up to you. 我建议你把它们放在默认的servlet映射(/)中,但这取决于你。 In any case your one-stop-shop security configuration is a servlet configuration file, not a root context (so you need to load it with a DispatcherServlet not a ContextLoaderListener ). 在任何情况下,您的一站式安全配置都是servlet配置文件,而不是根上下文(因此您需要使用DispatcherServlet而不是ContextLoaderListener加载它)。 This would be the same as in the sample (you need a servlet init param in web.xml), but there is nothing to stop you adding your own additional servlets (as long as the mappings don't clash of course). 这与示例中的相同(您需要在web.xml中使用servlet init参数),但没有什么可以阻止您添加自己的附加servlet(只要映射不会发生冲突)。

The authentication question is different. 身份验证问题不同。 The OAuth2 spec recommends that the /token endpoint is secured with Basic Authentication, so the prompt is a good thing in principle, although I can see that you tried to avoid it. OAuth2规范建议使用基本身份验证来保护/ token端点,因此提示原则上是一件好事,尽管我可以看到您试图避免它。 Putting secrets in form fields like you are doing is not really secure enough to be used in a production system, but if for some reason you need it you can use the ClientCredentialsTokenEndpointFilter (as you did). 在你正在做的表单字段中放置秘密并不足以在生产系统中使用,但如果由于某种原因你需要它,你可以使用ClientCredentialsTokenEndpointFilter (就像你一样)。 The reason that filter is not working might have been because you are sending a GET (not a POST), which is an even worse idea for security purposes than using the filter in the first place, but I don't see the flag being set anywhere that switches on POST-only validation in the filter (although I recommend you set it if you use this thing in anger anywhere). 过滤器无法正常工作的原因可能是因为您正在发送GET(而不是POST),出于安全目的,这比首先使用过滤器更糟糕,但我没有看到标志被设置在过滤器中打开仅POST验证的任何地方(虽然我建议你设置它,如果你在愤怒的地方使用这个东西)。

You haven't shown 2 Spring XML files but your web.xml refers to 2. I think the problem ultimately will be traceable to the fact that your have them mixed up or bean definitions duplicated across the two. 您没有显示2个Spring XML文件,但是您的web.xml指的是2.我认为问题最终将可追溯到这样一个事实,即您将它们混合在一起或者bean两个中的bean定义重复。 Maybe you can clarify that (or switch to loading a single file from the DispatcherServlet as recommended above)? 也许您可以澄清一下(或者如上所述切换到从DispatcherServlet加载单个文件)?

You can avoid the login page using a configuration like this: 您可以使用以下配置来避免登录页面:

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    ...

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http
            .authorizeRequests()
                .antMatchers("/").permitAll()
            .and()
                .authorizeRequests().anyRequest().hasRole("USER")
            .and()
                .csrf()
                .requireCsrfProtectionMatcher(new AntPathRequestMatcher("/**")).disable();
        // @formatter:on
    }
    ...
}

By default this method include a login page. 默认情况下,此方法包括登录页面。 With this new implementation in case you try to do a request without token a 403 error page will be displayed (you also can manage this error in order to redirect to a customized page) 使用此新实现,如果您尝试在没有令牌的情况下执行请求,将显示403错误页面(您还可以管理此错误以重定向到自定义页面)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在 Spring OAuth2 中配置安全性:身份验证请求的访问被拒绝 - Configure security in Spring OAuth2: Access is denied for authentication request 为Oauth和Http Basic身份验证配置Spring Security - Configuring Spring Security for Oauth and Http Basic authentication Spring Security Oauth2:访问令牌无效/过期时的回退 - Spring Security Oauth2: Fallback when access token is invalid/expired Spring Security + OAuth,如果缺少访问令牌,则进行回退 - Spring Security + OAuth, fallback if access token absent 使用Spring Security(非OAuth)使用登录名,密码和Facebook访问令牌的身份验证方法 - Authentication methods using login, password and Facebook access token using Spring Security(not OAuth) Spring 安全性 - 使用请求主机名进行令牌身份验证 - Spring Security - Token authentication with request host name 春季安全oauth2 JWT刷新令牌返回“身份验证失败:invalid_token无法将访问令牌转换为JSON” - spring security oauth2 JWT refresh token returns “Authentication failed: invalid_token Cannot convert access token to JSON” 对同一资源使用 Oauth2 或 Http-Basic 身份验证的 Spring Security - Spring security with Oauth2 or Http-Basic authentication for the same resource <spring security>在同一应用程序中具有 OAuth2 和基本身份验证</spring> - <Spring Security> Having OAuth2 and basic authentication in the same application Spring security oauth2 - 无法访问 /oauth/token 路由 - Spring security oauth2 - Can't access /oauth/token route
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM