我正在尝试将Spring Security集成到我的Web应用程序中。只要您整合整个身份验证和授权过程,这似乎很容易做到。
然而,身份验证和授权似乎都是如此耦合,以至于我理解如何拆分这些进程并独立于授权获得身份验证非常耗时。
身份验证过程在我们的系统外部(基于单点登录),并且无法修改。然而,一旦用户成功完成此过程,它就会加载到会话中,包括角色。
我们要努力实现的是将此信息用于Spring Security的授权过程,也就是说,强制它从用户会话中获取角色,而不是通过身份验证提供程序获取角色。
有没有办法实现这个目标?
答案 0 :(得分:22)
如果您的身份验证已使用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);
}
答案 1 :(得分:3)
是的,这是可能的。 Spring Security(与Spring的大部分内容一样)是接口驱动的,因此您可以选择性地为框架的不同部分插入自己的实现。
更新: Spring的授权和身份验证机制协同工作 - 身份验证机制将对用户进行身份验证,并在安全上下文中插入各种GrantedAuthority
实例。然后由授权机构检查这些内容以允许/禁止某些操作。
请使用非答案,了解有关如何使用预先存在的身份验证的详细信息。如何从会话中获取详细信息(例如角色)的详细信息当然取决于您的具体设置。但是,如果您放入由SSO系统在会话中预先填充的角色派生的GrantedAuthority
实例,您将能够在授权逻辑中使用它们。
从参考文档(稍加编辑,我的重点):
你可以(和许多用户一样)写 他们自己的过滤器或MVC控制器 提供互操作性 不是的身份验证系统 基于Spring Security。例如, 您可能正在使用Container Managed 认证,使当前 用户可从
ThreadLocal
或。{JNDI
位置。 或者你可能会为...工作 拥有传统专有权的公司 认证系统,这是一个 企业“标准”,你 几乎无法控制。在这样的 这种情况很容易搞定 Spring Security工作,仍然 提供授权功能。 您需要做的就是编写一个过滤器 (或同等的)读取 来自的第三方用户信息 位置,建立一个春天 特定于安全的Authentication
对象,把它放到SecurityContextHolder
。这很容易 做到这一点,它是一个 完全支持的集成方法。
答案 2 :(得分:2)
处理身份验证的服务器应该将用户重定向到向其传递某种密钥的应用程序(CAS SSO中的令牌)。然后,应用程序使用密钥向身份验证服务器询问关联的用户名和角色。使用此信息创建传递给授权管理器的安全上下文。这是SSO登录工作流程的简化版本 请查看CAS SSO和CAS 2 Architecture 如果您需要更多信息,请告诉我。
答案 3 :(得分:1)
我们有相同的要求,我们必须使用弹簧安全性仅用于授权目的。我们使用Siteminder进行身份验证。您可以在http://codersatwork.wordpress.com/2010/02/13/use-spring-security-for-authorization-only-not-for-authentication/
找到有关如何在http://code.google.com/p/spring-security-with-authorization-only/source/browse/ 使用spring security security身份验证授权部分的更多详细信息我还在{{3}}
添加了源代码和测试用例答案 4 :(得分:1)
我正在尝试使用我们自己的授权来理解CAS身份验证,并且因为Spring Security中的User对象总是希望填写密码并且我们在我们的场景中不关心密码而感到困惑。阅读Surabh的帖子之后,似乎诀窍是返回一个没有填写密码的自定义User对象。我会尝试一下,看看它是否适用于我的情况。希望链中的其他代码不会期望用户对象中的密码。
答案 5 :(得分:1)
我使用授权:
将授权相关的bean注入我自己的bean:
@Autowired
private AccessDecisionManager accessDecisionManager;
@Autowired
FilterSecurityInterceptor filterSecurityInterceptor;
使用此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);
答案 6 :(得分: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 pre-authentication过滤器,并以类似的方式进行。 链接示例:http://www.learningthegoodstuff.com/2014/12/spring-security-pre-authentication-and.html