Spring Security - OAuth2 和 CustomAuthenticationProvider。如何为每个配置不同的 URL 模式?

Posted

技术标签:

【中文标题】Spring Security - OAuth2 和 CustomAuthenticationProvider。如何为每个配置不同的 URL 模式?【英文标题】:Spring Security - OAuth2 and CustomAuthenticationProvider. How to configure different URL pattern for each one? 【发布时间】:2019-11-21 19:19:50 【问题描述】:

我的项目有两个身份验证提供程序:Google OAuth2 客户端(oauth2 启动器依赖项)和第二个自定义 AuthenticationProvider

我有两个antMatcher/api/**/app/**

是否可以使用 OAuth2 授权 /app/** 并使用我的自定义身份验证提供程序授权 /api/**

因为我不想为 REST API 启用 OAuth2,但希望为应用程序的其余部分启用 OAuth SSO。

如何为不同的身份验证提供者指定不同的 URL 模式?

编辑

按照我的配置(Spring Boot 2.0.2):

@Configuration
@EnableWebSecurity
class SecurityConfiguration : WebSecurityConfigurerAdapter() 

    override fun configure(http: HttpSecurity) 
        http.authorizeRequests()
            .antMatchers("/health").permitAll()
            .anyRequest().authenticated()
            .and()
            .oauth2Login()
            .permitAll()
    

尝试了不同的配置,但都没有成功

【问题讨论】:

能否添加 OAuth2 和自定义身份验证配置?还展示了如何注册过滤器、身份验证管理和提供者。可能是某些设置不正确。你的 spring security oauth 和 spring boot 版本是什么? @user2683814 我已经用更多细节编辑了我的问题 【参考方案1】:

AuthenticationProvider 有一个方法:supports(Class authentication) 它接受身份验证令牌,如果它返回 false,则 AuthenticationManager 将不会调用该 Provider。

因此您可以在 Authentication Token 中放置一个自定义字段来指示正在调用哪个 URI,Authentication 接口有一个 getDetails() 方法返回一个 Object,如果您可以提供其他信息。

为此,您需要创建自定义 AuthenticationDetails 和 AuthenticationDetailsS​​ource,您可以扩展 WebAuthenticationDetails 和 WebAuthenticationDetailsS​​ource。 WebAuthenticationDetailsS​​ource 有一个 buildDetails 方法,可让您访问 HttpServletRequest。

【讨论】:

谢谢。我可以在我的自定义身份验证提供程序上执行此操作,但是如何禁用 OAuth 的某些 URL 模式? 您是否考虑过设置 2 个独立的过滤器链?这就是我过去做这类事情的方式。如果您创建 2 个实现 WebSecurityConfigurerAdapter 的安全类,spring 将配置 2 个过滤器链。一个过滤器链可以用于 /api 和 /app。它使事情保持良好和独立,您可以使用 @Order 注释来确定应该首先评估哪个。 Spring 将针对 uri 尝试每个过滤器链,直到有匹配项,然后不会匹配任何其他项。 javacodegeeks.com/2017/08/… 我尝试了两个单独的过滤器链,但似乎 oauth 过滤器正在全局应用。出于将 oauth2 提供程序限制为 antMatcher 子集的想法,让其他人 antMatcher 用于自定义 jwt 身份验证提供程序【参考方案2】:

由于您有两个身份验证提供程序,您需要配置两个身份验证管理器。这是一个示例 XML 配置供您参考:

<security:authentication-manager id="appAuthenticationManager">
    <security:authentication-provider ref="appAuthenticationProvider"/>
</security:authentication-manager>

<security:authentication-manager id="apiAuthenticationManager">
    <security:authentication-provider ref="apiAuthenticationProvider"/>
</security:authentication-manager>

然后为端点配置安全保护规则。

<sec:filter-security-metadata-source id="appServerSecurityMetadataSource"
                                     request-matcher="ant"
                                     use-expressions="true">
    <sec:intercept-url pattern="/oauth/check_token" access="isFullyAuthenticated() and hasRole('PRIVATE_SERVICE')"/>
    <sec:intercept-url pattern="/oauth/token" access="isFullyAuthenticated() and hasRole('PRIVATE_SERVICE')"/>
    <sec:intercept-url pattern="/oauth/jwt-token" access="isFullyAuthenticated() and hasRole('PRIVATE_SERVICE')"/>
    <sec:intercept-url pattern="/**" access="denyAll()"/>

    <sec:expression-handler ref="securityExpressionHandler"/>
</sec:filter-security-metadata-source>


<sec:filter-security-metadata-source id="apiServerSecurityMetadataSource"
                                     request-matcher="ant"
                                     use-expressions="true">
    <sec:intercept-url pattern="/users/**" access="isFullyAuthenticated() and hasRole('ACTIVE_USER')"/>
    <sec:intercept-url pattern="/**" access="denyAll()"/>

    <sec:expression-handler ref="securityExpressionHandler"/>
</sec:filter-security-metadata-source>

然后配置过滤器安全拦截器:(为apiAuthenticationManager配置类似的拦截器)

<bean id="appSecurityInterceptorFilter" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
    <property name="authenticationManager" ref="appAuthenticationManager"/>
    <property name="accessDecisionManager" ref="accessDecisionManager"/>
    <property name="securityMetadataSource" ref="appServerSecurityMetadataSource"/>
</bean>

最后一步是注册这些过滤器 bean:

<bean id="appServerSecurityFilterRegistration" class="org.springframework.boot.web.servlet.FilterRegistrationBean">
    <property name="filter" ref="appSecurityInterceptorFilter"/>
    <property name="enabled" value="false"/>
</bean>

编辑:绕过来自整个过滤器链的一些请求:

为所有 /api/** 请求创建路径匹配器。

<bean id="apiRequestMatcher" class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
    <constructor-arg index="0" value="/api/**"/>
</bean>

创建一个空过滤器链以绕过/api/** 请求的所有过滤器。

<bean id="apiFilterChain" class="org.springframework.security.web.DefaultSecurityFilterChain">
    <constructor-arg name="requestMatcher" ref="apiRequestMatcher"/>
    <constructor-arg name="filters">
        <list/>
    </constructor-arg>
</bean>

最后,注册这个过滤器链代理。

<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
    <constructor-arg>
        <list>
            <ref bean="apiFilterChain"/>
        </list>
    </constructor-arg>
</bean>

要将这些请求委托给您的自定义提供商,请按照我之前分享的步骤操作。

您也可以尝试,&lt;http pattern="/api/**" security="none"/&gt; 绕过过滤器链。 Spring 3.1 将 filters=”none” 替换为 security=”none”

【讨论】:

不起作用。 oauth2 提供程序仍处理 /api/** 匹配器。有什么办法可以让 oauth2 提供者完全忽略 /api/** 匹配器,并且 spring-security 将此匹配器委托给 CustomProvider? 但现在对/api/** 的所有请求都是不安全的 是的,它就是这么做的。我在编辑之前共享的步骤应该可以完成预期的工作。现在,我想如果不检查您的身份验证配置,人们很难为您提供帮助。 仅通过网络安全配置无法找出问题所在。请尝试配置并分享特定问题。

以上是关于Spring Security - OAuth2 和 CustomAuthenticationProvider。如何为每个配置不同的 URL 模式?的主要内容,如果未能解决你的问题,请参考以下文章

Spring-Security OAuth2 设置 - 无法找到 oauth2 命名空间处理程序

Spring Security OAuth2 v5:NoSuchBeanDefinitionException:'org.springframework.security.oauth2.jwt.Jwt

针对授权标头的Spring Security OAuth2 CORS问题

OAuth2.0学习(4-1)Spring Security OAuth2.0 - 代码分析

Spring Security---Oauth2详解

如何使用spring-security,oauth2调整实体的正确登录?