package com.huajie.cloud.auth.config;
/**
* Description:
*
* @author IceZhang
* Copyright 2018-2019 创捷运维智能科技有限公司
* All rights reserved.
* @version: 1.0
* Reversion:
* 1.0 - 新建
*/
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.NullRememberMeServices;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.web.filter.GenericFilterBean;
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;
/**
* 参考 {@link org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter}
* @version 0.1
* @auth admin.
* @time 2018/2/25 13:04
* @since 0.1
*/
public class CodeFilter extends GenericFilterBean {
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
//验证码拦截路径
private static final String CODE_ANT_URL = "/oauth/mobile";
private static final String SPRING_SECURITY_FORM_CAPTCHA_KEY = "code";
private String captchaParameter = SPRING_SECURITY_FORM_CAPTCHA_KEY;
private boolean postOnly = true;
//请求路径匹配
private RequestMatcher requiresAuthenticationRequestMatcher;
private RememberMeServices rememberMeServices = new NullRememberMeServices();
private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler(CODE_ANT_URL); //设置验证失败重定向路径
public CodeFilter() {
this.requiresAuthenticationRequestMatcher = new AntPathRequestMatcher(CODE_ANT_URL, "POST");
}
public CodeFilter(RequestMatcher requiresAuthenticationRequestMatcher) {
Assert.notNull(requiresAuthenticationRequestMatcher,"requiresAuthenticationRequestMatcher cannot be null");
this.requiresAuthenticationRequestMatcher = requiresAuthenticationRequestMatcher;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 不是需要过滤的路径,执行下一个过滤器
if (!requiresAuthentication(request, response)) {
filterChain.doFilter(request, response);
return;
}
if (logger.isDebugEnabled()) {
logger.debug("Request is to process authentication");
}
Authentication authResult;
try {
authResult = this.attemptAuthentication(request, response);
if (authResult == null) {
logger.error("Authentication is null!");
// return immediately as subclass has indicated that it hasn't completed
// authentication
return;
}
} catch (InternalAuthenticationServiceException failed) {
logger.error("An internal error occurred while trying to authenticate the user.",failed);
return;
} catch (AuthenticationException failed) {
logger.error("Authentication failed.", failed);
//Authentication failed
unsuccessfulAuthentication(request, response, failed);
return;
}
//认证成功,执行下个过滤器
filterChain.doFilter(request, response);
}
private Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
//获取验证码
String captcha = request.getParameter(captchaParameter);
if (captcha == null) {
captcha = "";
}
captcha = captcha.trim();
CodeAuthenticationToken authRequest = new CodeAuthenticationToken(captcha);
//这里可以直接省略掉,用provider直接验证
CodeAuthenticationManager manager = new CodeAuthenticationManager(new CodeAuthenticationProvider());
return manager.authenticate(authRequest);
}
/**
* 比较需要过滤的请求路径
*
* @param request
* @param response
* @return
*/
protected boolean requiresAuthentication(HttpServletRequest request,
HttpServletResponse response) {
return requiresAuthenticationRequestMatcher.matches(request);
}
/**
* 处理验证码认证失败
* 参考 {@link org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter}
* Default behaviour for unsuccessful authentication.
* <ol>
* <li>Clears the {@link SecurityContextHolder}</li>
* <li>Stores the exception in the session (if it exists or
* <tt>allowSesssionCreation</tt> is set to <tt>true</tt>)</li>
* <li>Informs the configured <tt>RememberMeServices</tt> of the failed login</li>
* <li>Delegates additional behaviour to the {@link AuthenticationFailureHandler}.</li>
* </ol>
*/
protected void unsuccessfulAuthentication(HttpServletRequest request,
HttpServletResponse response, AuthenticationException failed)
throws IOException, ServletException {
SecurityContextHolder.clearContext();
if (logger.isDebugEnabled()) {
logger.debug("Authentication request failed: " + failed.toString(), failed);
logger.debug("Updated SecurityContextHolder to contain null Authentication");
logger.debug("Delegating to authentication failure handler " + failureHandler);
}
rememberMeServices.loginFail(request, response);
failureHandler.onAuthenticationFailure(request, response, failed);
}
}
package com.huajie.cloud.auth.config;
/**
* Description:
*
* @author IceZhang
* Copyright 2018-2019 创捷运维智能科技有限公司
* All rights reserved.
* @version: 1.0
* Reversion:
* 1.0 - 新建
*/
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;
/**
* 参考 {@link org.springframework.security.authentication.UsernamePasswordAuthenticationToken}
* @version 0.1
* @auth admin.
* @time 2018/2/25 11:24
* @since 0.1
*/
public class CodeAuthenticationToken extends AbstractAuthenticationToken{
/**
* 验证码
*/
private Object captcha;
/**
* 验证码验证标识
* true:通过
* false:错误
*/
private boolean flag;
public CodeAuthenticationToken() {
super(null);
}
public CodeAuthenticationToken(Object captcha) {
super(null);
this.captcha = captcha;
this.flag = false;
setAuthenticated(false);
}
public CodeAuthenticationToken(Collection<? extends GrantedAuthority> authorities, Object captcha) {
super(authorities);
this.captcha = captcha;
this.flag = false;
super.setAuthenticated(true); // must use super, as we override
}
@Override
public Object getCredentials() {
return null;
}
@Override
public Object getPrincipal() {
return null;
}
public Object getCaptcha() {
return captcha;
}
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
if (isAuthenticated) {
throw new IllegalArgumentException(
"Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
}
super.setAuthenticated(false);
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
package com.huajie.cloud.auth.config;
/**
* Description:
*
* @author IceZhang
* Copyright 2018-2019 创捷运维智能科技有限公司
* All rights reserved.
* @version: 1.0
* Reversion:
* 1.0 - 新建
*/
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.util.Assert;
/**
* 验证码验证类
* 参考 {@link org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider}
* @version 0.1
* @auth admin.
* @time 2018/2/25 11:32
* @since 0.1
*/
public class CodeAuthenticationProvider implements AuthenticationProvider {
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
logger.debug("custom captcha authentication");
Assert.isInstanceOf(CodeAuthenticationToken.class, authentication,"错误的类");
CodeAuthenticationToken custCaptchaToken = (CodeAuthenticationToken) authentication;
String captcha = custCaptchaToken.getCaptcha().toString();
if(captcha.equals("")){
logger.debug("验证码为空");
throw new CodeAuthenticationException("验证码错误!");
}
//写死一个验证码,具体可以自己修改
if(!captcha.equals("1000")){
logger.debug("验证码错误");
throw new CodeAuthenticationException("验证码错误!");
}
//返回验证成功对象
custCaptchaToken.setFlag(true);
return custCaptchaToken;
}
@Override
public boolean supports(Class<?> authentication) {
return (CodeAuthenticationToken.class.isAssignableFrom(authentication));
}
}
package com.huajie.cloud.auth.config;
/**
* Description:
*
* @author IceZhang
* Copyright 2018-2019 创捷运维智能科技有限公司
* All rights reserved.
* @version: 1.0
* Reversion:
* 1.0 - 新建
*/
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.util.Assert;
/**
* 由于是拓展spring security的验证,不能在ProviderManager中调用到,这里单独处理一个验证管理器。
* @version 0.1
* @auth admin.
* @time 2018/2/25 11:27
* @since 0.1
*/
public class CodeAuthenticationManager implements AuthenticationManager {
/**
* 自己实现的验证码认证器
*/
private AuthenticationProvider provider;
public CodeAuthenticationManager(AuthenticationProvider provider) {
Assert.notNull(provider, "provider cannot be null");
this.provider = provider;
}
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
return this.provider.authenticate(authentication);
}
}
package com.huajie.cloud.auth.config;
/**
* Description:
*
* @author IceZhang
* Copyright 2018-2019 创捷运维智能科技有限公司
* All rights reserved.
* @version: 1.0
* Reversion:
* 1.0 - 新建
*/
import org.springframework.security.core.AuthenticationException;
/**
* 自定义验证码验证失败异常
* @version 0.1
* @auth admin.
* @time 2018/2/25 11:37
* @since 0.1
*/
public class CodeAuthenticationException extends AuthenticationException {
public CodeAuthenticationException(String msg, Throwable t) {
super(msg, t);
}
public CodeAuthenticationException(String msg) {
super(msg);
}
}