22

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

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

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

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

有什么办法可以做到这一点?

4

7 回答 7

24

如果您的身份验证已经使用 SSO 服务完成,那么您应该使用 spring security 的预身份验证过滤器之一。然后你可以指定一个 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);
}
于 2009-08-24T15:35:32.140 回答
3

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

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

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

从参考文档(稍微编辑,我强调):

您可以(许多用户也这样做)编写自己的过滤器或 MVC 控制器,以提供与不基于 Spring Security 的身份验证系统的互操作性。例如,您可能正在使用容器管理的身份验证,它使当前用户可以从一个ThreadLocalJNDI位置访问。或者,您可能为一家拥有遗留专有身份验证系统的公司工作,这是一个您几乎无法控制的企业“标准”。在这种情况下,很容易让 Spring Security 工作,并且仍然提供授权功能。您需要做的就是编写一个过滤器(或等效的),从某个位置读取第三方用户信息,构建一个 Spring Security 特定的Authentication 对象,并将其放到 SecurityContextHolder. 这样做很容易,而且它是一种完全支持的集成方法。

于 2009-08-24T13:08:41.290 回答
2

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

于 2009-08-24T14:58:08.410 回答
1

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

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

于 2010-02-17T17:07:37.670 回答
1

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

于 2010-02-18T16:36:19.747 回答
1

我通过以下方式使用授权:

  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);
    
于 2011-09-16T12:06:29.833 回答
0

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

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

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预身份验证过滤器,并以类似的方式进行操作。示例链接: http: //www.learningthegoodstuff.com/2014/12/spring-security-pre-authentication-and.html

于 2018-11-27T08:21:02.653 回答