首页 文章

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

提问于
浏览
5

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

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

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

我怎样才能做到这一点?以有效的方式?

谢谢!

2 回答

  • 3

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

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

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

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

  • 1

    使用上面的答案作为指导,这是我创建的一个后处理器的工作示例,它允许您指定要向验证器提供的登录表单变量,以及一个示例自定义验证器,用于检查登录表单中的terms_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;
        }
    }
    

    这是使用它的自定义Authenticator:

    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));
        }
    }
    

相关问题