如何使用自定义过滤器映射为Spring安全过滤器链添加自定义过滤器?

时间:2016-03-10 12:30:25

标签: spring spring-mvc spring-security servlet-filters spring-annotations

我想检查验证码,如果使用想要登录,如果验证码是正确的,请调用filterChain.doFilter()继续验证,如果验证码不正确,则将用户登录到登录页面以重新输入用户名,密码和验证码。 所以,我想将CaptchaFilter / login filterMapping放在春季安全装配链的第一个。

的login.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html; charset=UTF-8" language="java" pageEncoding="UTF-8" session="true" %>
<html>
<head>
    <title>Login Page</title>
</head>
<body onload='document.loginForm.username.focus();'>
<div id="login-box">

    <form name='loginForm' action="<c:url value='/login' />" method='POST'>
        <table>
            <tr>
                <td>User:</td>
                <td><input type='text' name='username'></td>
            </tr>
            <tr>
                <td>Password:</td>
                <td><input type='password' name='password'/>
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    <img id="imgCaptcha" src="<c:url value = '/j-captcha.jpg' />" onclick='this.src="<c:url value='/j-captcha.jpg'/>";' style="cursor: pointer"/>
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    <input name="jcaptcha" type="text" placeholder="captcha"/>
                </td>
            <tr>
                <td colspan='2'><input name="submit" type="submit" value="submit"/></td>
            </tr>
        </table>
    </form>
</div>
</body>
</html>

CaptchaFilter

public class CaptchaFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        if (request.getParameter("jcaptcha") != null) {
            checkCaptcha(request, response, filterChain);
        } else {
            filterChain.doFilter(request, response);
        }
    }

    private void checkCaptcha(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        try {
            String userCaptchaResponse = request.getParameter("jcaptcha");
            boolean isResponseCorrect = CaptchaService.getInstance().validateResponseForID(request.getRequestedSessionId(), userCaptchaResponse);
            if (isResponseCorrect) {
                filterChain.doFilter(request, response);
            } else {
                String url = request.getHeader("referer").replaceAll("[&?]error.*?(?=&|\\?|$)", "");
                url += "?error=" + SecurityUtility.CAPTCHA_IS_WRONG;

                redirect(request, response, url);
            }
        } catch (Exception e) {
            e.printStackTrace();
            filterChain.doFilter(request, response);
        }
    }

    private void redirect(HttpServletRequest request, HttpServletResponse response, String url) {
        try {
            response.sendRedirect(request.getContextPath() + url);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void destroy() {

    }
}

SpringSecurityConfig:

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    @Qualifier("userDetailsService")
    UserDetailsService userDetailsService;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests().antMatchers("/admin/**")
                .access("hasRole('ROLE_USER')").and().formLogin()
                .loginPage("/login").failureUrl("/login?error")
                .usernameParameter("username")
                .passwordParameter("password")
                .and().logout().logoutSuccessUrl("/login?logout")
                .and().exceptionHandling().accessDeniedPage("/403");
    }
}

SpringWebConfig

@EnableWebMvc
@Configuration
@ComponentScan({"com.rgh.*"})
@EnableTransactionManagement
@Import({SpringSecurityConfig.class})
public class SpringWebConfig {
    @Bean
    public SessionFactory sessionFactory() {
        LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(dataSource());
        builder.scanPackages("com.rgh.*.model").addProperties(getHibernateProperties());
        return builder.buildSessionFactory();
    }

    private Properties getHibernateProperties() {
        // set and return properties
    }

    @Bean(name = "dataSource")
    public BasicDataSource dataSource() {
        // set and return datasource
    }

    @Bean
    public HibernateTransactionManager txManager() {
        return new HibernateTransactionManager(sessionFactory());
    }
}

SpringWebInitializer

public class SpringWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringWebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/", "/rest/*"};
    }
}

SpringSecurityInitializer

public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {

}

我刚接触第4春季和春季java配置。

1 个答案:

答案 0 :(得分:2)

您可以像这样添加过滤器:

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
...
http.addFilterAfter(yourFilter, CsrfFilter.class);
...
}

还有其他方法addFilterBefore(..)和addFilter(..)来添加过滤器。 addFilterBefore和addFilterAfter期望作为第二个参数的一个过滤器类,它是SecurityFilterChain的一部分,它们将相对于它添加。 addFilter需要一些我从未尝试过的编译器。

要查找SecurityFilterChain中实际存在的过滤器类,请在控制器方法中设置断点,并在堆栈中搜索SecurityFilterChain(或DefaultSecurityFilterChain)。在那里你可以看到配置了哪些过滤器类,例如在DefaultSecurityFilterChain.fiters中 找到第一个过滤器类,而不是使用addFilterBefore来添加CaptchaFilter。