View Javadoc
1   package cn.home1.oss.lib.security.internal;
2   
3   import static cn.home1.oss.lib.security.internal.preauth.PreAuthTokenFilter.ATTR_PRINCIPAL;
4   import static cn.home1.oss.lib.security.starter.FormAuthConfiguration.FORM_AUTHENTICATION_ENTRYPOINT;
5   import static org.apache.commons.lang3.StringUtils.isBlank;
6   
7   import cn.home1.oss.lib.security.api.GenericUser;
8   import cn.home1.oss.lib.security.api.Security;
9   import cn.home1.oss.lib.security.api.VerifyCodeProvider;
10  import cn.home1.oss.lib.webmvc.api.RequestResolver;
11  
12  import lombok.NonNull;
13  import lombok.Setter;
14  import lombok.extern.slf4j.Slf4j;
15  
16  import org.springframework.beans.factory.annotation.Autowired;
17  import org.springframework.beans.factory.annotation.Qualifier;
18  import org.springframework.core.env.Environment;
19  import org.springframework.security.authentication.BadCredentialsException;
20  import org.springframework.security.core.AuthenticationException;
21  import org.springframework.security.core.context.SecurityContextHolder;
22  import org.springframework.security.web.AuthenticationEntryPoint;
23  import org.springframework.web.filter.GenericFilterBean;
24  
25  import java.io.IOException;
26  
27  import javax.servlet.FilterChain;
28  import javax.servlet.ServletException;
29  import javax.servlet.ServletRequest;
30  import javax.servlet.ServletResponse;
31  import javax.servlet.http.HttpServletRequest;
32  import javax.servlet.http.HttpServletResponse;
33  
34  /**
35   * TODO Note: Not a bean, avoid auto pick-up.
36   * before UsernamePasswordAuthenticationFilter.
37   *
38   * <p>
39   * Created by zhanghaolun on 16/7/14.
40   * </p>
41   */
42  @Setter
43  @Slf4j
44  public class VerifyCodeFilter extends GenericFilterBean {
45  
46    /**
47     * will be invoked when authentication fails. Typically an instance of {@link
48     * org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint}.
49     */
50    @Qualifier(FORM_AUTHENTICATION_ENTRYPOINT)
51    @Autowired
52    @NonNull
53    private AuthenticationEntryPoint formAuthenticationEntryPoint;
54  
55    @Autowired(required = false)
56    @NonNull
57    private VerifyCodeProvider codeVerifyProvider;
58  
59    @Autowired
60    @NonNull
61    private RequestResolver requestResolver;
62  
63    @Override
64    public void doFilter( //
65      final ServletRequest req, final ServletResponse res, final FilterChain chain //
66    ) throws IOException, ServletException {
67      final HttpServletRequest request = (HttpServletRequest) req;
68      final HttpServletResponse response = (HttpServletResponse) res;
69  
70      try {
71        if (this.authenticationIsRequired(request)) {
72          final GenericUser principal = (GenericUser) request.getAttribute(ATTR_PRINCIPAL);
73          this.authenticate(request, principal);
74        }
75      } catch (final AuthenticationException failed) {
76        SecurityContextHolder.clearContext();
77  
78        if (log.isTraceEnabled()) {
79          log.trace("AUTH authentication failed. not login.", failed);
80        }
81  
82        this.formAuthenticationEntryPoint.commence(request, response, failed);
83        return;
84      }
85  
86      chain.doFilter(request, response);
87    }
88  
89    private boolean authenticationIsRequired(final HttpServletRequest request) {
90      // TODO fix this, 有context-path的情况下可能不对
91      return Security.authenticationIsRequired() && this.requestResolver.isLoginRequest(request);
92    }
93  
94    private void authenticate( //
95      final HttpServletRequest request, //
96      final GenericUser principal //
97    ) throws AuthenticationException {
98      final String code = request.getParameter("verifycode");
99      if (isBlank(code)) {
100       throw new BadCredentialsException("verifycode is required");
101     }
102     final String uuid = principal.getUuid();
103     final Boolean match = this.codeVerifyProvider.match(uuid, code);
104     if (!match) {
105       throw new BadCredentialsException("verifycode not match");
106     }
107   }
108 
109   public String getCodeUrl() {
110     return this.codeVerifyProvider.getCodeUrl();
111   }
112 
113   @Autowired
114   @Override
115   public void setEnvironment(final Environment environment) {
116     super.setEnvironment(environment);
117   }
118 }