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 和 AuthenticationDetailsSource,您可以扩展 WebAuthenticationDetails 和 WebAuthenticationDetailsSource。 WebAuthenticationDetailsSource 有一个 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>
要将这些请求委托给您的自定义提供商,请按照我之前分享的步骤操作。
您也可以尝试,<http pattern="/api/**" security="none"/>
绕过过滤器链。 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问题