【问题标题】:How to protect the same resource using both spring-session and spring-security-oauth如何使用 spring-session 和 spring-security-oauth 保护相同的资源
【发布时间】:2018-01-18 18:31:32
【问题描述】:

我需要使用两种身份验证, 对于 web,我们使用 @EnableRedisHttpSession,对于其他消费者(例如移动设备),我们使用 @EnableAuthorizationServer 和 @EnableResourceServer。

假设我们尝试保护两个身份验证机制通用的控制器,例如 /api/v1/test

我遇到了障碍。 我只能使用一种身份验证方案 如果我设置 @WebSecurityConfigurerAdapter @order(2) 和 @ResourceServerConfigurerAdapter @order(3) 那么我只能通过网络访问资源

如果我设置 @ResourceServerConfigurerAdapter @order(2) 和 @WebSecurityConfigurerAdapter @order(3) 那么只有 OAuth 有效。

我无法同时使用这两种机制。我们如何使两者协同工作,例如,如果请求来自网络,请使用负责该请求的过滤器,如果请求来自移动设备,请使用适当的过滤器. web 使用 cookie 和 API Consumers 使用 Authorization : Bearer header。

请帮忙

【问题讨论】:

    标签: spring-boot spring-security-oauth2 spring-session


    【解决方案1】:

    听起来很奇怪。我建议您查看 REST API 的使用方式以及浏览器用户应该使用它的原因。最好将 Web 视图和 REST API 分开,不要混用。

    但是,回答您的问题“我可以同时对某个 URI 使用两种身份验证吗” - 是的,您可以。
    您需要自定义 RequestMatcher 来决定如何路由传入请求。

    所以:

    • 对于“API 消费者” - 检查 Authorization 标头是否存在 包含“承载者”
    • 对于“浏览器用户” - 只需反转第一条规则

    代码示例:

    public abstract class AntPathRequestMatcherWrapper implements RequestMatcher {
    
        private AntPathRequestMatcher delegate;
    
        public AntPathRequestMatcherWrapper(String pattern) {
            this.delegate = new AntPathRequestMatcher(pattern);
        }
        
        @Override
        public boolean matches(HttpServletRequest request) {
            if (precondition(request)) {
                return delegate.matches(request);
            }
            return false;
        }
    
        protected abstract boolean precondition(HttpServletRequest request);
    
    }
    
    1. OAuth2 身份验证
    @EnableResourceServer
    @Configuration
    public class ResourceServerConfigurer extends ResourceServerConfigurerAdapter {
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.requestMatcher(new AntPathRequestMatcherWrapper("/api/v1/test") {
                @Override
                protected boolean precondition(HttpServletRequest request) {
                    return String.valueOf(request.getHeader("Authorization")).contains("Bearer");
                }
            }).authorizeRequests().anyRequest().authenticated();
        }
    }
    
    1. Web 身份验证
    @Configuration
    @EnableWebSecurity
    public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.requestMatcher(new AntPathRequestMatcherWrapper("/api/v1/test") {
                @Override
                protected boolean precondition(HttpServletRequest request) {
                    return !String.valueOf(request.getHeader("Authorization")).contains("Bearer");
                }
            }).authorizeRequests().anyRequest().authenticated();
        }
    }
    

    使用此配置,可以为一个 URI /api/v1/test 使用两种不同的身份验证类型。

    另外,我强烈推荐阅读 Dave Syer 关于 Spring Security 架构的文章,了解它是如何工作的:
    https://spring.io/guides/topicals/spring-security-architecture/#_web_security

    【讨论】:

    • @Ankur 不客气 :) 但无论如何,它仍然是一个肮脏的黑客
    • 假设我有可以与两种身份验证一起使用的通用功能,我应该复制该功能而不是重复使用它。
    猜你喜欢
    • 2016-02-11
    • 2012-12-26
    • 1970-01-01
    • 2017-08-01
    • 2015-12-11
    • 2013-08-06
    • 2011-07-22
    • 2015-12-09
    • 2011-04-17
    相关资源
    最近更新 更多