如何在SpringSecurityFilterChain中添加我自己的自定义过滤器来检查spring java config中的验证码?

时间:2016-03-15 20:50:42

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

我有一个e CaptchaFilter类,用于在用户登录时检查验证码的值。在spring的xml配置中,我配置如下:

    <filter>
        <filter-name>CheckCaptchaFilter</filter-name>
        <filter-class>org.baharan.cms.common.filters.security.CheckCaptchaFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CheckCaptchaFilter</filter-name>
        <url-pattern>/j_spring_security_check</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

这是登录表单:

<form name="form" action="<c:url value='/j_spring_security_check' />" method='POST'>
<!-- labels and inputs here-->
<c:if test="${sessionScope.LOGIN_ATTEMPTS >= 3}">
    <div class="form-group">
    <img src="<c:url value = '/j-captcha.jpg' />" id="imgCaptcha" onclick='this.src="<c:url value = '/j-captcha.jpg' />"' />
        <input type="text" name="jcaptcha" />
    </div>
</c:if>
</form>

这是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;
        checkLoginAttempts(request);

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

    private void checkLoginAttempts(HttpServletRequest request) {
        HttpSession session = request.getSession();
        try {
            int loginAttempts = Integer.parseInt(session.getAttribute("LOGIN_ATTEMPTS").toString());
            loginAttempts++;
            session.setAttribute("LOGIN_ATTEMPTS", loginAttempts);
        }
        catch (Exception ex) {
            session.setAttribute("LOGIN_ATTEMPTS", 1);
        }
    }

    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() {

    }
}

通过这种方式,如果用户输入验证码错误,它会将用户引导至登录页面,而不会调用filterChain.doFilter(request, response);

现在,我想在spring java配置中执行此操作,这是我的SpringWebInitializer类:

public class SpringWebInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(SpringWebConfig.class);
        rootContext.register(SpringSecurityConfig.class);
        rootContext.register(SpringPersistanceConfig.class);
        rootContext.setServletContext(servletContext);
        ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(rootContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/", "/rest/*");

        FilterRegistration.Dynamic filter = servletContext.addFilter("openSessionInViewFilter", OpenSessionInViewFilter.class);
        filter.setInitParameter("sessionFactoryBeanName", "sessionFactory");
        filter.addMappingForServletNames(null, true, "dispatcher");

        servletContext.addListener(new ContextLoaderListener(rootContext));
    }
}

和这个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.headers().frameOptions().sameOrigin();
        http.authorizeRequests()
            .antMatchers("/assets/**", "/panel/login**","/panel/login.jsp**", "/login**", "/login.jsp**").permitAll()
            .antMatchers("/panel/**", "/rest/**").access("hasRole('ROLE_USER')")
            .and().formLogin().loginPage("/login")
            .failureUrl("/login?error")
            .defaultSuccessUrl("/panel")
            .usernameParameter("username").passwordParameter("password")
            .and().logout().logoutSuccessUrl("/login?logout")
            .and().csrf().disable();
    }
}

这是BaseController来显示观点:

@Controller
public class BaseController {

    @RequestMapping(value = "/panel**", method = RequestMethod.GET)
    public ModelAndView adminPage() {
        ModelAndView model = new ModelAndView();
        model.setViewName("/panel/admin");
        return model;
    }

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public ModelAndView login() {
        ModelAndView model = new ModelAndView();
        model.setViewName("/panel/login");

        return model;
    }
}

我很困惑,我是初次使用java配置的新手,请帮助!!

概念性问题:

这是在春天实施验证码的正确和最佳方式吗?如果没有,请解释正确的方法。

0 个答案:

没有答案