spring-security - 如果下游服务以 401 响应,如何在 Zuul API 网关中触发 OAuth2 身份验证

标签 spring-security spring-boot spring-cloud spring-security-oauth2 spring-cloud-netflix

我正在试验三个 Spring 云(启动)应用程序。

  • 端口 9999 上的身份验证服务器
  • 在端口 9008
  • 上具有安全和不安全端点的基本后端示例
  • 一个基本的 Zuul API 网关,有几个路由(安全和不安全)到端口 9000
  • 上的后端样本

    后端示例启动应用程序被注释为资源服务器 (@EnableResourceServer) 并使用 ResourceServerConfigurerAdapter 保护一些端点

    当我第一次调用 Zuul API 网关上 protected 路由之一时,我被重定向到身份验证服务器的登录页面。在那里登录后,我被重定向到我最初请求的安全路由。 protected 后端样本端点的行为符合预期,这意味着后端样本确实获得了所提供 token 的授予角色。如果我遇到我没有适当角色的后端示例端点,我会收到 OAuth 403 响应。在这种情况下一切都很好。

    我们还需要将遗留服务置于 API 网关之后。这些渲染 html 并且应该能够在用户点击那里的安全区域时触发登录。我们无法在 API 网关路由级别保护这些区域,因为遗留后端对许多不同的子 URL 具有复杂(增长)的权限模型。

    有谁知道在这种下游 401 响应情况下使 Spring-cloud API 网关重定向到身份验证服务器的登录名的好方法吗?我在“post”类型的 ZuulFilter 中尝试了一个简单的重定向,但由于响应已经在那里提交而失败。

    后端示例 application.yml;

    server:
        port: 9008
        
    security:
      oauth2:
        resource:
          userInfoUri: http://localhost:9999/uaa/user


    API网关应用程序.yml:

    server:
        port: 9008
    zuul:
       proxy:
          addProxyHeaders: true
       sensitive-headers: 
       routes:
          unsecured-backend-sample:
             path: /unsecured-backend-sample/**
             url: http://localhost:9008
          authorized-backend-sample:
             path: /authorized-backend-sample/**
             url: http://localhost:9008/
          user-role-secured-backend-sample:
             path: /user-role-secured-backend-sample/**
             url: http://localhost:9008/
          xxx-role-secured-backend-sample:
             path: /xxx-role-secured-backend-sample/**
             url: http://localhost:9008/
    security:
      oauth2:
        client:
          accessTokenUri: http://localhost:9999/uaa/oauth/token
          userAuthorizationUri: http://localhost:9999/uaa/oauth/authorize
          clientId: acme
          clientSecret: acmesecret
        resource:
          userInfoUri: http://localhost:9999/uaa/user
    

    最佳答案

    我终于找到了一个对我有用的解决方案。我写了一个 ZuulFilter,它只处理 401 响应并重定向到登录。它还将被拒绝的请求保存在 HTTP session 请求缓存中,以便 SavedRequestAwareAuthenticationSuccessHandler 可以将您重定向回最初请求的下游服务 URL。

    @Component
    public class LoginOnDownstreamUnauthorizedResponseFilter extends ZuulFilter {
    
        private Logger logger = LoggerFactory.getLogger(getClass());
    
        private AuthenticationEntryPoint authenticationEntryPoint = new LoginUrlAuthenticationEntryPoint("/login");
    
        private RequestCache requestCache = new HttpSessionRequestCache();
    
        @Override
        public boolean shouldFilter() {
            // Only handle downstream 401s
            return RequestContext.getCurrentContext().getResponse().getStatus() == HttpStatus.SC_UNAUTHORIZED;
        }
    
        @Override
        public Object run() {
    
            RequestContext ctx = RequestContext.getCurrentContext();
            HttpServletRequest request = ctx.getRequest();
            HttpServletResponse response = ctx.getResponse();
    
            // We need to put the rejected request in the request cache for SavedRequestAwareAuthenticationSuccessHandler
            // to find it's way back to the initial request URI after successful authentication.
            requestCache.saveRequest(request, response);
    
            String text = String.format("Downstream service %s responded with a status code 401.", request.getRequestURI());
            logger.debug(text + " Calling Authentication entry point.");
            try {
                authenticationEntryPoint.commence(request, response, new InsufficientAuthenticationException(text));
            } catch (IOException | ServletException e) {
                logger.error("Failed to redirect to Authentication entry point", e);
            }
    
            return null;
        }
    
        @Override
        public String filterType() {
            return "post";
        }
    
        @Override
        public int filterOrder() {
            // make sure to run before SendResponseFilter
            return 500;
        }
    
    }
    

    关于spring-security - 如果下游服务以 401 响应,如何在 Zuul API 网关中触发 OAuth2 身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40936900/

    相关文章:

    javascript - Spring Security CSRF token 不适用于同一 JSP 中的 AJAX 调用和表单提交

    java - 使用 Redis 在 Spring Boot 中将对象添加到 Http Session 失败

    java - 弹性4j - 请求超时

    java - MySQL中如何处理锁定帐户

    spring - 微服务之间的原子操作

    java - 在 spring security 中禁用特定 url 的缓存

    authentication - 使用 spring security 在连续 3 次登录尝试失败后阻止用户帐户

    openid - 使用 Spring Security 3 进行身份验证时收到来自 Google 的 414 Request-URI Too Large

    spring-boot - Spring Cloud Consul健康检查配置

    java - Spring Cloud Config Server 也可以将配置更新推送到远程 git 存储库吗?