如何在Spring获取之前捕获Spring Security登录表单?

时间:2012-01-27 03:12:34

标签: spring-security

我有一个带有用户名和密码的Spring登录表单,它指向/ myapp / j_spring_security_check。

我希望在Spring收到请求之前有人提交登录表单时拦截表单提交。

基本上,我希望能够查看用户输入以查看它是否符合某些要求。如果没有,应用程序将把用户带回登录表单。如果用户输入符合要求,则流程将转到Spring身份验证。

我该怎么做?以有效的方式?

谢谢!

2 个答案:

答案 0 :(得分:3)

您可以使用常规Spring Security功能执行此操作。步骤是:

  1. 实施自定义WebAuthenticationDetailsSourceWebAuthenticationDetailsWebAuthenticationDetails将捕获您要验证的额外表单字段。

    注意:在Spring 3.0中,您需要use a BeanPostProcessor to configure WebAuthenticationDetailsSource进入UsernamePasswordAuthenticationFilter。在Spring 3.1中,您可以直接在<form-login>命名空间配置中执行此操作。

  2. 实施自定义AuthenticationProvider并在authenticate()中检查WebAuthenticationDetails,如果验证失败则抛出AuthenticationException。在您的登录页面中检查此例外。

  3. 或者,您可以创建一个Filter进行验证并在Spring Security过滤器之前添加它。

答案 1 :(得分:1)

使用上面的答案作为指导,这是我创建的后处理器的一个工作示例,它允许您指定要向验证器提供的登录表单变量,以及一个示例自定义验证器,用于检查term_of_service复选框值。登录表单。

在Spring配置中:

<bean id="authFormDetailsPostProcessor" class="com.sefaira.authauth.AuthFormDetailsPostProcessor">
  <property name="formVarNames" value="terms_of_service_accepted"/>
</bean>

AuthFormDetailsPostProcessor.java:

public class AuthFormDetailsPostProcessor implements BeanPostProcessor {

    private String [] formVarNames;

    public void setFormVarNames (String formVarNames) { 
    this.formVarNames = formVarNames.split (",");
    }

    public static class Details extends WebAuthenticationDetails {

    private Map<String, String> map;

    public Details (HttpServletRequest request, String [] parameters) {
        super (request);

        this.map = new HashMap<String, String>();
        for (String parameter : parameters) {
        this.map.put (parameter.trim(), request.getParameter (parameter.trim()));
        }
    }

    public String get (String name) {
        return map.get(name);
    }
    }

    public Object postProcessAfterInitialization(Object bean, String name) {
        if (bean instanceof UsernamePasswordAuthenticationFilter) {
            ((UsernamePasswordAuthenticationFilter)bean).setAuthenticationDetailsSource(
                    new AuthenticationDetailsSource() {
                        public Object buildDetails(Object context) {

                if (formVarNames == null) {
                throw new RuntimeException ("AuthFormDetailsPostProcessor bean requires a formVarNames property, specifying a comma-delimited list of form vars to provide in the details object.");
                }

                return new Details ((HttpServletRequest) context, formVarNames);
                        }
                    });
        }
        return bean;
    }

    public Object postProcessBeforeInitialization(Object bean, String name) {
        return bean;
    }
}

这是使用它的自定义身份验证器:

public class AuthServiceAuthenticator implements AuthenticationProvider {

   @Override
    public Authentication authenticate (Authentication authentication) throws AuthenticationException {

    String email = (String) authentication.getPrincipal();  
    String password = (String) authentication.getCredentials();

    AuthFormDetailsPostProcessor.Details details = (AuthFormDetailsPostProcessor.Details) authentication.getDetails();

    // see if they checked the terms_of_service checkbox        
    String termsOfServiceVar = details.get ("terms_of_service_accepted");
    boolean termsOfServiceAccepted = (termsOfServiceVar != null && termsOfServiceVar.equals ("on"));

        // ... do your custom authentication ...

        return authentication;  // or a new authentication object
    }

    @Override
    public boolean supports(Class<? extends Object> authentication) {
        return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
    }
}