Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring security validate captcha via filter的值错误_Java_Spring Mvc_Spring Boot_Spring Security_Captcha - Fatal编程技术网

Java Spring security validate captcha via filter的值错误

Java Spring security validate captcha via filter的值错误,java,spring-mvc,spring-boot,spring-security,captcha,Java,Spring Mvc,Spring Boot,Spring Security,Captcha,我正在研究SpringBoot,使用SpringSecurity进行身份验证登录。我完成了这部分。现在,我想在登录页面中实现captcha。我这样做了,但有时会出问题。这里是我的源代码 登录页面 <form th:action="@{/j_spring_security_check}" method="post"> <tr> <th align="left" width="30%"> &l

我正在研究SpringBoot,使用SpringSecurity进行身份验证登录。我完成了这部分。现在,我想在登录页面中实现captcha。我这样做了,但有时会出问题。这里是我的源代码

登录页面

<form th:action="@{/j_spring_security_check}" method="post">
<tr>
                <th align="left" width="30%">
                    <label for="userId">User Id</label>
                </th>
                <td width="70%">

                    <input type="text" style="width: 150px" name="userId" autocomplete="off"/>
                </td>
            </tr>
            <tr>
                <th align="left" width="30%">
                    Password
                </th>
                <td width="70%">

                    <input type="PASSWORD" style="width: 150px" name="password" autocomplete="off"/>
                </td>
            </tr>
            <tr>
                <th align="left" width="30%">
                    Answer
                </th>
                <td width="70%">
                    <input type="text" name="logonAnswer" style="width: 150px"/>
                </td>
            </tr>
            <tr>
                <td align="right">&nbsp;
                </td>
                <td align="left">
                    <div id="captcha"
                         style="cursor: pointer; height: 30px; width: 150px; display: inline-block; float: left"><img
                            th:src="@{/captcha}"/></div>
                    <div id="captchaRefresh" class="refresh-btn" title="Click to get other Captcha"></div>
                </td>
            </tr>
</form>
验证码验证过滤器中的

@Autowired
    UserDetailsServiceImpl userDetailsService;

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

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpSession session = request.getSession(false);
        if (userDetailsService != null
                && request.getParameter("logonAnswer") != null
                && !request.getParameter("logonAnswer").equals("")
                && session != null && request.getParameter("logonAnswer").equalsIgnoreCase(session.getAttribute("wirecardmposcaptcha").toString())) {
            userDetailsService.setCaptchaOK(true);
        }

        chain.doFilter(request, response);
    }
和用户详细信息简化

private boolean captchaOK;

    public void setCaptchaOK(boolean captchaOK) {
        this.captchaOK = captchaOK;
    }

    @Override
    @Transactional
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Users user = userRepository.findByUserId(username);
        if (user == null) {
            throw new UsernameNotFoundException("UserId or Password invalid");
        }

        if (!captchaOK)
            throw new InternalAuthenticationServiceException("Invalid Captcha");

        Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
        Set<Roles> roles = user.getRoles();
        for (Roles role : roles) {
            grantedAuthorities.add(new SimpleGrantedAuthority(role.getRoleName()));
        }

        return new org.springframework.security.core.userdetails.User(user.getUserId(), user.getPassword(), user.getEnabled().equals("true"), true, true, true, grantedAuthorities);
    }
因此,我在captcha过滤器中调试captchaOk的值多次更改。我不确定我的做法是否正确

请看一看并提出意见


谢谢。

之前,我定制了一个过滤器来验证spring boot应用程序中的验证码。也许你的定制过滤器有问题。您可以参考我的实现:

1.CaptchaAuthenticationFilter:在创建验证代码时将其放入会话中,然后从会话中获取验证代码以在此处进行验证

import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * The filter to verify captcha.
 */
public class CaptchaAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private String processUrl;

    public CaptchaAuthenticationFilter(String defaultFilterProcessesUrl, String failureUrl) {
        super(defaultFilterProcessesUrl);
        this.processUrl = defaultFilterProcessesUrl;
        setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(failureUrl));
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res=(HttpServletResponse)response;
        if(processUrl.equals(req.getServletPath()) && "POST".equalsIgnoreCase(req.getMethod())){
            String expect = req.getSession().getAttribute("YZM").toString();

            //remove from session
            req.getSession().removeAttribute("YZM");

            if (expect != null && !expect.equals(req.getParameter("verifyCode"))){
                unsuccessfulAuthentication(req, res, new InsufficientAuthenticationException("Wrong verification code."));
                return;
            }
        }
        chain.doFilter(request, response);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {
        return null;
    }
}
2.将其配置为spring security:

 @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        // add filter here
        http.addFilterBefore(new CaptchaAuthenticationFilter("/login", "/login?error2"), UsernamePasswordAuthenticationFilter.class);
        http.authorizeRequests()
                .antMatchers("/").hasRole("USER")
                .antMatchers("/index").hasRole("USER")
                .antMatchers("/message/*").hasRole("USER")
                .anyRequest().permitAll()
                .and().formLogin().loginPage("/login").defaultSuccessUrl("/index").failureUrl("/login?error1").permitAll()
                .and().rememberMe().tokenValiditySeconds(60*60*7).key("message")
                .and().logout().logoutUrl("/logout").logoutSuccessUrl("/login").permitAll();
    }
3.注意上面的failureUrl
/login?error 2
。如果验证码验证失败,那么请求将被重定向到那里。您可以在页面上捕获错误,如下所示:

<div class="clearfix">
    <div th:if="${param.error1}">
        <div class="btn btn-xs btn-danger">
            <i class="icon-bolt bigger-110"></i>
            Wrong username or password!
        </div>
    </div>

    <div th:if="${param.error2}">
        <div class="btn btn-xs btn-danger">
            <i class="icon-bolt bigger-110"></i>
            Wrong verification code!
        </div>
    </div>
</div>

错误的用户名或密码!
错误的验证码!

之前,我定制了一个过滤器来验证spring boot应用程序中的验证码。也许你的定制过滤器有问题。您可以参考我的实现:

1.CaptchaAuthenticationFilter:在创建验证代码时将其放入会话中,然后从会话中获取验证代码以在此处进行验证

import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * The filter to verify captcha.
 */
public class CaptchaAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private String processUrl;

    public CaptchaAuthenticationFilter(String defaultFilterProcessesUrl, String failureUrl) {
        super(defaultFilterProcessesUrl);
        this.processUrl = defaultFilterProcessesUrl;
        setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(failureUrl));
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res=(HttpServletResponse)response;
        if(processUrl.equals(req.getServletPath()) && "POST".equalsIgnoreCase(req.getMethod())){
            String expect = req.getSession().getAttribute("YZM").toString();

            //remove from session
            req.getSession().removeAttribute("YZM");

            if (expect != null && !expect.equals(req.getParameter("verifyCode"))){
                unsuccessfulAuthentication(req, res, new InsufficientAuthenticationException("Wrong verification code."));
                return;
            }
        }
        chain.doFilter(request, response);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {
        return null;
    }
}
2.将其配置为spring security:

 @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        // add filter here
        http.addFilterBefore(new CaptchaAuthenticationFilter("/login", "/login?error2"), UsernamePasswordAuthenticationFilter.class);
        http.authorizeRequests()
                .antMatchers("/").hasRole("USER")
                .antMatchers("/index").hasRole("USER")
                .antMatchers("/message/*").hasRole("USER")
                .anyRequest().permitAll()
                .and().formLogin().loginPage("/login").defaultSuccessUrl("/index").failureUrl("/login?error1").permitAll()
                .and().rememberMe().tokenValiditySeconds(60*60*7).key("message")
                .and().logout().logoutUrl("/logout").logoutSuccessUrl("/login").permitAll();
    }
3.注意上面的failureUrl
/login?error 2
。如果验证码验证失败,那么请求将被重定向到那里。您可以在页面上捕获错误,如下所示:

<div class="clearfix">
    <div th:if="${param.error1}">
        <div class="btn btn-xs btn-danger">
            <i class="icon-bolt bigger-110"></i>
            Wrong username or password!
        </div>
    </div>

    <div th:if="${param.error2}">
        <div class="btn btn-xs btn-danger">
            <i class="icon-bolt bigger-110"></i>
            Wrong verification code!
        </div>
    </div>
</div>

错误的用户名或密码!
错误的验证码!