【问题标题】:spring-security: authorization without authenticationspring-security:无需身份验证的授权
【发布时间】:2010-11-22 06:28:16
【问题描述】:

我正在尝试将 Spring Security 集成到我的 Web 应用程序中。只要你整合了认证和授权的整个过程,这似乎很容易做到。

但是,身份验证和授权似乎如此耦合,以至于我要了解如何拆分这些流程并独立于授权获取身份验证非常耗时。

身份验证过程在我们的系统外部(基于单点登录),无法修改。然而,一旦用户成功完成了这个过程,它就会被加载到会话中,包括角色。

我们试图实现的是利用这些信息来进行 Spring Security 的授权过程,也就是说,强制它从用户 session 中获取角色,而不是通过 authentication-provider 来获取它。

有什么方法可以实现吗?

【问题讨论】:

    标签: authentication session authorization spring-security


    【解决方案1】:

    如果您的身份验证已经使用 SSO 服务完成,那么您应该使用 spring security 的pre-authentication filters 之一。然后你可以指定一个 UserDetails 服务(可能是自定义的),它将使用预先认证的用户原则来填充 GrantedAuthority 的

    SpringSecurity 包括几个预认证过滤器,包括 J2eePreAuthenticatedProcessingFilter 和 RequestHeaderPreAuthenticatedProcessingFilter。如果您找不到适合您的应用程序,也可以自己编写,而且并不难,只要您知道您的 SSO 实现在请求中的什么位置填充数据。 (这当然取决于实现。)

    只需实现Filter 接口并在doFilter 方法中执行类似的操作:

    public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
    
        // principal is set in here as a header or parameter. you need to find out 
        // what it's named to extract it
        HttpServletRequest req = (HttpServletRequest) request; 
    
        if (SecurityContextHolder.getContext().getAuthentication() == null) {
            // in here, get your principal, and populate the auth object with 
            // the right authorities
            Authentication auth = doAuthentication(req); 
            SecurityContextHolder.getContext().setAuthentication(auth);
        }
    
        chain.doFilter(request, response);
    }
    

    【讨论】:

    • 您好,我一直在做这个。您的回答非常有帮助,尽管现在我不得不将这个问题推迟几天。我会回来的,让你知道事情的进展。谢谢!
    • 这对我们的应用程序来说还不够......我还需要将 SecurityContext 添加到会话中,如下所示: session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());跨度>
    • @markitus82 您是否为此编写了任何自定义用户详细信息服务。我被同样的故事困住了。
    【解决方案2】:

    是的,这是可能的。 Spring Security(与 Spring 的大多数其他部分一样)是接口驱动的,因此您可以有选择地为框架的不同部分插入自己的实现。

    更新: Spring 的授权和身份验证机制协同工作 - 身份验证机制将对用户进行身份验证并在安全上下文中插入各种 GrantedAuthority 实例。然后授权机制会检查这些以允许/禁止某些操作。

    关于如何使用预先存在的身份验证的详细信息,请使用 nont 的答案。您如何从会话中获取详细信息(例如角色)的详细信息当然取决于您的特定设置。但是,如果您放入源自 SSO 系统在会话中预填充的角色的 GrantedAuthority 实例,您将能够在您的授权逻辑中使用它们。

    来自参考文档(稍作编辑,重点强调):

    您可以(并且许多用户都可以)编写 他们自己的过滤器或 MVC 控制器 提供互操作性 认证系统不是 基于 Spring Security。例如, 您可能正在使用容器管理 使当前的身份验证 用户可通过ThreadLocal 或 JNDI 位置。 或者你可以为一个 拥有传统专利的公司 身份验证系统,这是一个 您所依据的企业“标准” 几乎没有控制权。在这样的 情况很容易得到 Spring Security 工作,仍然 提供授权能力。 您需要做的就是编写一个过滤器 (或等价物)读取 第三方用户信息来自 位置,建立一个弹簧 安全特定Authentication 对象,并将其放在 SecurityContextHolder。这很容易 做到这一点,这是一个 完全支持的集成方法。

    【讨论】:

    • 但是有必要配置一个AuthenticationProvider吗?
    • 是的,但它不一定是授权提供者的不同对象:您可以创建一个实现两者的类(因为您的 SSO 系统似乎也给了您两者)。
    • 问题是我的应用程序中的登录表单(身份验证)是由外部系统执行的。我所拥有的只是用户会话,并且用户已经过身份验证。我想知道如何从会话中获取 userId 和角色以使用 Spring Authorization。
    • 您必须向进行身份验证的外部系统询问用户 ID 和角色。
    【解决方案3】:

    处理身份验证的服务器应该将用户重定向到传递给它的某种密钥(CAS SSO 中的令牌)的应用程序。然后应用程序使用密钥向身份验证服务器询问相关的用户名和角色。使用此信息创建传递给授权管理器的安全上下文。这是 SSO 登录工作流程的一个非常简化的版本。
    看看CAS SSO 和CAS 2 Architecture。
    如果您需要更多信息,请告诉我。

    【讨论】:

      【解决方案4】:

      我们也有同样的要求,我们只能将 spring security 用于授权目的。我们使用 Siteminder 进行身份验证。您可以在http://codersatwork.wordpress.com/2010/02/13/use-spring-security-for-authorization-only-not-for-authentication/ 处找到有关如何使用 Spring Security 的授权部分而不是身份验证的更多详细信息

      我还在http://code.google.com/p/spring-security-with-authorization-only/source/browse/添加了源代码和测试用例

      【讨论】:

        【解决方案5】:

        我试图用我们自己的 Authorization 来理解 CAS 身份验证并且感到困惑,因为 Spring Security 中的 User 对象总是希望填写密码,而在我们的场景中我们并不关心这一点。在阅读了 Surabh 的帖子之后,似乎诀窍是返回一个没有填写密码的自定义 User 对象。我会尝试一下,看看它是否适用于我的情况。希望链中的其他代码不会期望用户对象中的密码。

        【讨论】:

          【解决方案6】:

          我是这样使用授权的:

          1. 将授权相关的bean注入我自己的bean中:

            @Autowired
            private AccessDecisionManager    accessDecisionManager;
            @Autowired
            FilterSecurityInterceptor        filterSecurityInterceptor;
            
          2. 通过这个来使用这个bean:

            FilterInvocation fi = new FilterInvocation(rundata.getRequest(), rundata.getResponse(), new FilterChain() {
            
                public void doFilter(ServletRequest arg0, ServletResponse arg1) throws IOException, ServletException {
                    // TODO Auto-generated method stub
            
                }
            });
            FilterInvocationDefinitionSource objectDefinitionSource = filterSecurityInterceptor.getObjectDefinitionSource();
            ConfigAttributeDefinition attr = objectDefinitionSource.getAttributes(fi);
            Authentication authenticated = new Authentication() {
            
                ...........
            
                public GrantedAuthority[] getAuthorities() {
                    GrantedAuthority[] result = new GrantedAuthority[1];
                    result[0] = new GrantedAuthorityImpl("ROLE_USER");
                    return result;
                }
            };
            accessDecisionManager.decide(authenticated, fi, attr);
            

          【讨论】:

            【解决方案7】:

            我也花了很多时间研究如何在没有身份验证的情况下实现自定义授权。
            身份验证过程在我们的系统之外(基于单点登录)。 我已经做到了,如下所述,它有效!!! (我相信还有很多其他更好的方法,但是这种方法很适合我的场景)

            场景:用户已通过外部系统的身份验证,并且授权所需的所有信息都存在于请求中

            1。 需要创建安全配置,启用全局方法安全,如下所示。

            @Configuration
            @EnableWebSecurity
            @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
            class SpringWebSecurityConfig extends WebSecurityConfigurerAdapter {
            
                @Override
                protected void configure(final HttpSecurity http) throws Exception {
                }
            }
            

            2.) 实现 Spring PermissionEvaluator 来授权请求​​是被允许还是被拒绝

            @Component
            public class CustomPermissionEvaluator implements PermissionEvaluator {
            
                public boolean authorize(final String groups, final String role) {
                    boolean allowed = false;
                    System.out.println("Authorizing: " + groups + "...");
                    if (groups.contains(role)) {
                        allowed = true;
                        System.out.println(" authorized!");
                    }
                    return allowed;
                };
            
                @Override
                public boolean hasPermission(final Authentication authentication, final Object groups, final Object role) {
                    return authorize((String) groups, (String) role);
                };
            
                @Override
                public boolean hasPermission(final Authentication authentication, final Serializable targetId, final String targetType, final Object permission) {
                    return authorize((String) targetId, (String) permission);
                };
            }
            

            3.) 添加 MethodSecurityConfig

            @Configuration
            @EnableGlobalMethodSecurity(prePostEnabled = true)
            public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
            
                @Override
                protected MethodSecurityExpressionHandler createExpressionHandler() {
                    DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
                    expressionHandler.setPermissionEvaluator(new CustomPermissionEvaluator());
                    return expressionHandler;
                }
            }
            

            4.) 在控制器中添加@PreAuthorize,如下所示。在此示例中,用户的所有组都存在于请求标头中,键为“availableUserGroups”。 然后将其传递给 CustomPermissionEvaluator 以验证授权。请注意,spring 会自动将 Authentication 对象传递给方法“hasPermission”。 因此,如果您想加载用户并使用 spring 'hasRole' 方法进行检查,则可以使用它。

            @PreAuthorize("hasPermission(#userGroups, 'ADMIN')")
            @RequestMapping(value = "/getSomething")
            public String getSomething(@RequestHeader(name = "availableUserGroups") final String userGroups) {
                return "resource allowed to access";
            }
            

            处理其他场景: 1.) 在您想要在执行授权之前加载用户的场景。您可以使用 spring pre-authentication 过滤器,并以类似的方式进行操作。 示例链接:http://www.learningthegoodstuff.com/2014/12/spring-security-pre-authentication-and.html

            【讨论】:

              猜你喜欢
              • 2014-05-11
              • 2011-07-17
              • 1970-01-01
              • 2014-05-24
              • 2016-08-15
              • 2021-02-24
              • 2017-05-10
              • 2023-02-09
              • 2015-05-22
              相关资源
              最近更新 更多