完成短信验证码验证,以及短信登录开发,抽离出公共的常量
This commit is contained in:
+2
-2
@@ -37,7 +37,7 @@ public class PropertiesUtil {
|
||||
}
|
||||
public void loadProperties(String projectPath){
|
||||
//2.将mybatisStart.properties配置文件加载到输入流中
|
||||
File file = new File( projectPath+"/src/main/resources/"+PROPERTIES_PATH);
|
||||
File file = new File( projectPath+ "/src/main/resources/"+PROPERTIES_PATH);
|
||||
if (file.exists()){
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
@@ -54,6 +54,6 @@ public class PropertiesUtil {
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+107
-92
@@ -1,5 +1,7 @@
|
||||
package com.micro.fast.security.browser.config;
|
||||
|
||||
import com.micro.fast.security.core.authentication.mobile.SmsCodeAuthenticationSecurityConfig;
|
||||
import com.micro.fast.security.core.master.SecurityConstants;
|
||||
import com.micro.fast.security.core.master.SecurityProperties;
|
||||
import com.micro.fast.security.core.validate.code.filter.ValidateCodeFilter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -37,104 +39,117 @@ import javax.sql.DataSource;
|
||||
*/
|
||||
@Configuration
|
||||
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
/**
|
||||
* 注入身份认证框架配置参数对象
|
||||
*/
|
||||
@Autowired
|
||||
private SecurityProperties securityProperties;
|
||||
/**
|
||||
* 注入身份认证框架配置参数对象
|
||||
*/
|
||||
@Autowired
|
||||
private SecurityProperties securityProperties;
|
||||
|
||||
/**
|
||||
* 注入身份认证成功后续处理对象
|
||||
*/
|
||||
@Autowired
|
||||
private AuthenticationSuccessHandler msAuthenticationSuccessHandler;
|
||||
/**
|
||||
* 注入身份认证成功后续处理对象
|
||||
*/
|
||||
@Autowired
|
||||
private AuthenticationSuccessHandler msAuthenticationSuccessHandler;
|
||||
|
||||
/**
|
||||
* 输入身份认证失败后后续处理对象
|
||||
*/
|
||||
@Autowired
|
||||
private AuthenticationFailureHandler msAuthenticationFailureHandler;
|
||||
/**
|
||||
* 输入身份认证失败后后续处理对象
|
||||
*/
|
||||
@Autowired
|
||||
private AuthenticationFailureHandler msAuthenticationFailureHandler;
|
||||
|
||||
/**
|
||||
* 需要注入数据源
|
||||
*/
|
||||
@Autowired
|
||||
@Qualifier("masterDataSource")
|
||||
private DataSource dataSource;
|
||||
/**
|
||||
* 需要注入数据源
|
||||
*/
|
||||
@Autowired
|
||||
@Qualifier("masterDataSource")
|
||||
private DataSource dataSource;
|
||||
|
||||
@Autowired
|
||||
private UserDetailsService userDetailsService;
|
||||
@Autowired
|
||||
private UserDetailsService userDetailsService;
|
||||
|
||||
/**
|
||||
* 自定义身份认证配置
|
||||
*
|
||||
* @param http
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
//创建自定义的验证码过滤器,填入身份认证失败处理对象
|
||||
ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
|
||||
validateCodeFilter.setAuthenticationFailureHandler(msAuthenticationFailureHandler);
|
||||
validateCodeFilter.setSecurityProperties(securityProperties);
|
||||
validateCodeFilter.afterPropertiesSet();
|
||||
http
|
||||
//添加自定义的验证码处理器,在用户密码校验过滤器之前
|
||||
.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
|
||||
//使用表单登录
|
||||
.formLogin()
|
||||
//自定义登录页面
|
||||
.loginPage("/authentication/require")
|
||||
//配置spring security登录接口的访问地址,用于在自定义的登录页面提交请求
|
||||
.loginProcessingUrl("/user/login")
|
||||
//定义身份认证成功后处理对象
|
||||
.successHandler(msAuthenticationSuccessHandler)
|
||||
//定义身份认证失败后处理对象
|
||||
.failureHandler(msAuthenticationFailureHandler)
|
||||
.and()
|
||||
//记住我功能的相关配置
|
||||
.rememberMe()
|
||||
//设置token的存储方式
|
||||
.tokenRepository(persistentTokenRepository())
|
||||
//设置过期秒数
|
||||
.tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())
|
||||
//设置获取用户信息后登录的方式
|
||||
.userDetailsService(userDetailsService)
|
||||
.and()
|
||||
.authorizeRequests()//下面是权限配置
|
||||
//当访问这个页面的时候不进行身份认证,对用户自定义的登录页也不进行权限认证
|
||||
.antMatchers("/user/login", "/code/*", "/authentication/require", securityProperties.getBrowser().getHtml()).permitAll()
|
||||
//任何请求
|
||||
.anyRequest()
|
||||
//都需要身份认证
|
||||
.authenticated()
|
||||
.and()
|
||||
//暂时关闭掉跨站请求攻击防护
|
||||
.csrf().disable();
|
||||
/**
|
||||
* 短信验证码登录的配置
|
||||
*/
|
||||
@Autowired
|
||||
private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;
|
||||
|
||||
}
|
||||
/**
|
||||
* 自定义身份认证配置
|
||||
*
|
||||
* @param http
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
//创建自定义的验证码过滤器,填入身份认证失败处理对象
|
||||
ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
|
||||
validateCodeFilter.setAuthenticationFailureHandler(msAuthenticationFailureHandler);
|
||||
validateCodeFilter.setSecurityProperties(securityProperties);
|
||||
validateCodeFilter.afterPropertiesSet();
|
||||
http
|
||||
//添加自定义的验证码处理器,在用户密码校验过滤器之前
|
||||
.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
|
||||
//使用表单登录
|
||||
.formLogin()
|
||||
//自定义登录页面
|
||||
.loginPage(SecurityConstants.LOGIN_PAGE)
|
||||
//配置spring security登录接口的访问地址,用于在自定义的登录页面提交请求
|
||||
.loginProcessingUrl(SecurityConstants.FORM_LOGIN_PROCESSOR_URI)
|
||||
//定义身份认证成功后处理对象
|
||||
.successHandler(msAuthenticationSuccessHandler)
|
||||
//定义身份认证失败后处理对象
|
||||
.failureHandler(msAuthenticationFailureHandler)
|
||||
.and()
|
||||
//记住我功能的相关配置,是基于cookie实现的,所以是浏览器特有的功能
|
||||
.rememberMe()
|
||||
//设置token的存储方式
|
||||
.tokenRepository(persistentTokenRepository())
|
||||
//设置过期秒数
|
||||
.tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())
|
||||
//设置获取用户信息后登录的方式
|
||||
.userDetailsService(userDetailsService)
|
||||
.and()
|
||||
.authorizeRequests()//下面是权限配置
|
||||
//当访问这个页面的时候不进行身份认证,对用户自定义的登录页也不进行权限认证
|
||||
.antMatchers(SecurityConstants.MOBILE_LOGIN_PROCESSOR_URI
|
||||
, SecurityConstants.FORM_LOGIN_PROCESSOR_URI
|
||||
, SecurityConstants.GET_VALIDATE_CODE_URI
|
||||
, SecurityConstants.LOGIN_PAGE
|
||||
, securityProperties.getBrowser().getHtml())
|
||||
.permitAll()
|
||||
//任何请求
|
||||
.anyRequest()
|
||||
//都需要身份认证
|
||||
.authenticated()
|
||||
.and()
|
||||
//暂时关闭掉跨站请求攻击防护
|
||||
.csrf().disable()
|
||||
//应用短信验证码登录的逻辑
|
||||
.apply(smsCodeAuthenticationSecurityConfig);
|
||||
|
||||
/**
|
||||
* 定义身份认证红密码的加密解密类的bean
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于记住我功能
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public PersistentTokenRepository persistentTokenRepository() {
|
||||
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
|
||||
jdbcTokenRepository.setDataSource(dataSource);
|
||||
//启动的时候创建表
|
||||
jdbcTokenRepository.setCreateTableOnStartup(true);
|
||||
return jdbcTokenRepository;
|
||||
}
|
||||
/**
|
||||
* 定义身份认证红密码的加密解密类的bean
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于记住我功能
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public PersistentTokenRepository persistentTokenRepository() {
|
||||
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
|
||||
jdbcTokenRepository.setDataSource(dataSource);
|
||||
//启动的时候创建表
|
||||
jdbcTokenRepository.setCreateTableOnStartup(true);
|
||||
return jdbcTokenRepository;
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -19,6 +19,7 @@ import java.io.IOException;
|
||||
/**
|
||||
* AuthenticationFailureHandler
|
||||
* 身份认证失败的后续处理类
|
||||
* @author lsy
|
||||
*/
|
||||
@Component("msAuthenticationFailureHandler")
|
||||
public class MsAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
|
||||
|
||||
+1
@@ -17,6 +17,7 @@ import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 身份认证成功后的处理类
|
||||
* @author lsy
|
||||
*/
|
||||
@Component("msAuthenticationSuccessHandler")
|
||||
public class MsAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
|
||||
|
||||
+3
-3
@@ -15,10 +15,10 @@ import org.springframework.stereotype.Component;
|
||||
* 自定义根据用户名获取密码方法替换spring security的默认逻辑
|
||||
* @author lsy
|
||||
*/
|
||||
@Component
|
||||
public class MsUserDetialsServiceImpl implements UserDetailsService {
|
||||
@Component("msUserDetailsServiceImpl")
|
||||
public class MsUserDetailsServiceImpl implements UserDetailsService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MsUserDetialsServiceImpl.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(MsUserDetailsServiceImpl.class);
|
||||
|
||||
|
||||
@Autowired
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
package com.micro.fast.security.browser.controller;
|
||||
|
||||
import com.micro.fast.security.core.master.SecurityConstants;
|
||||
import com.micro.fast.security.core.master.SecurityProperties;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
@@ -39,7 +40,7 @@ public class BrowserSecurityController {
|
||||
|
||||
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
|
||||
|
||||
@RequestMapping("/authentication/require")
|
||||
@RequestMapping(SecurityConstants.LOGIN_PAGE)
|
||||
@ResponseStatus(code = HttpStatus.UNAUTHORIZED)
|
||||
public String requireAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
//根据当前请求获取上一次请求的缓存
|
||||
@@ -57,7 +58,7 @@ public class BrowserSecurityController {
|
||||
}
|
||||
}
|
||||
//如果是异步请求的话就放回404状态码和提示信息
|
||||
return new String("访问的服务需要身份认证,需要引导用户到身份认证页面");
|
||||
return "访问的服务需要身份认证,需要引导用户到身份认证页面";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -4,10 +4,11 @@ import org.springframework.security.core.userdetails.User;
|
||||
|
||||
/**
|
||||
* 用于根据spring security传入的username获取用户的详细信息接口
|
||||
* @author lsy
|
||||
*/
|
||||
public interface UserService {
|
||||
/**
|
||||
*
|
||||
* 根据用户的username获取用户的身份认证信息
|
||||
* @param username
|
||||
* @return user
|
||||
*/
|
||||
|
||||
+8
-6
@@ -1,5 +1,6 @@
|
||||
package com.micro.fast.security.core.authentication.mobile;
|
||||
|
||||
import com.micro.fast.security.core.master.SecurityConstants;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
@@ -10,16 +11,17 @@ import org.springframework.util.Assert;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
||||
/**
|
||||
* 身份认证过滤器
|
||||
* @author lsy
|
||||
*/
|
||||
public class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
|
||||
|
||||
public static final String MICRO_FAST_MOBILE_KEY = "mobile";
|
||||
public static final String AUTHENTICATION_MOBILE_URL = "/authentication/mobile";
|
||||
|
||||
private String mobileParameter = MICRO_FAST_MOBILE_KEY;
|
||||
/**
|
||||
* 从请求中获取手机号参数的key
|
||||
*/
|
||||
private String mobileParameter = SecurityConstants.MOBILE_LOGIN_PROCESSOR_PARAM_MOBILE_KEY;
|
||||
|
||||
/**
|
||||
* 是不是只处理post请求
|
||||
@@ -27,10 +29,10 @@ public class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessin
|
||||
private boolean postOnly = true;
|
||||
|
||||
/**
|
||||
* 对/authentication/mobile路径的post请求进行身份认证
|
||||
* 对/authentication/mobile路径的post请求进行身份登录操作
|
||||
*/
|
||||
public SmsCodeAuthenticationFilter() {
|
||||
super(new AntPathRequestMatcher(AUTHENTICATION_MOBILE_URL, "POST"));
|
||||
super(new AntPathRequestMatcher(SecurityConstants.MOBILE_LOGIN_PROCESSOR_URI, "POST"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package com.micro.fast.security.core.authentication.mobile;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author lsy
|
||||
* 短信验证码登录的配置类
|
||||
*/
|
||||
@Component
|
||||
public class SmsCodeAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain,HttpSecurity>{
|
||||
|
||||
@Autowired
|
||||
@Qualifier("msAuthenticationSuccessHandler")
|
||||
private AuthenticationSuccessHandler authenticationSuccessHandler;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("msAuthenticationFailureHandler")
|
||||
private AuthenticationFailureHandler authenticationFailureHandler;
|
||||
|
||||
//todo 需要改成根据手机号获取用户的信息
|
||||
@Autowired
|
||||
@Qualifier("msUserDetailsServiceImpl")
|
||||
private UserDetailsService userDetailsService;
|
||||
|
||||
@Override
|
||||
public void configure(HttpSecurity http) throws Exception {
|
||||
|
||||
SmsCodeAuthenticationFilter smsCodeAuthenticationFilter = new SmsCodeAuthenticationFilter();
|
||||
//将短信验证码登录过滤器放入AuthenticationManager,方便后续调用
|
||||
smsCodeAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
|
||||
smsCodeAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler);
|
||||
smsCodeAuthenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler);
|
||||
|
||||
//将根据手机号获取用户信息的对象放入短信验证码的provider中
|
||||
SmsCodeAuthenticationProvider smsCodeAuthenticationProvider = new SmsCodeAuthenticationProvider();
|
||||
smsCodeAuthenticationProvider.setUserDetailsService(userDetailsService);
|
||||
//将自定义的provider放入authenticaionManger管理的集合中去
|
||||
http.authenticationProvider(smsCodeAuthenticationProvider)
|
||||
//将自定义的过滤器添加到用户账号密码校验过滤器后面
|
||||
.addFilterAfter(smsCodeAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
}
|
||||
}
|
||||
-1
@@ -12,7 +12,6 @@ public class BrowserProperties {
|
||||
|
||||
/**
|
||||
* 用户自自定义的登录页面,不能为空
|
||||
*
|
||||
*/
|
||||
@NotBlank
|
||||
private String html;
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.micro.fast.security.core.master;
|
||||
|
||||
/**
|
||||
* 身份认证框架常亮类
|
||||
* @author lsy
|
||||
*/
|
||||
public interface SecurityConstants {
|
||||
|
||||
/**
|
||||
* 触发身份认证请求的时候跳转到的uri
|
||||
*/
|
||||
String LOGIN_PAGE = "/authentication/require";
|
||||
|
||||
/**
|
||||
* 处理表单登录请求的uri
|
||||
*/
|
||||
String FORM_LOGIN_PROCESSOR_URI = "/user/login";
|
||||
|
||||
/**
|
||||
* 处理手机短信登录的uri
|
||||
*/
|
||||
String MOBILE_LOGIN_PROCESSOR_URI = "/authentication/mobile";
|
||||
|
||||
/**
|
||||
* 手机短信身份认证时从请求中获取手机号的key
|
||||
*/
|
||||
String MOBILE_LOGIN_PROCESSOR_PARAM_MOBILE_KEY = "mobile";
|
||||
|
||||
/**
|
||||
* 获取验证码的uri
|
||||
*/
|
||||
String GET_VALIDATE_CODE_URI = SecurityConstants.GET_VALIDATE_CODE_PREFIX+"*";
|
||||
|
||||
/**
|
||||
* 获取验证码请求的前缀
|
||||
*/
|
||||
String GET_VALIDATE_CODE_PREFIX = "/code/";
|
||||
|
||||
}
|
||||
+3
-2
@@ -1,5 +1,7 @@
|
||||
package com.micro.fast.security.core.validate.code.config.param;
|
||||
|
||||
import com.micro.fast.security.core.master.SecurityConstants;
|
||||
|
||||
/**
|
||||
* 图形验证码默认的配置
|
||||
* @author lsy
|
||||
@@ -19,10 +21,9 @@ public class ImageCodeProperties extends SmsCodeProperties{
|
||||
*/
|
||||
public ImageCodeProperties() {
|
||||
setLength(4);
|
||||
setUrl(SecurityConstants.FORM_LOGIN_PROCESSOR_URI);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
+3
-1
@@ -1,5 +1,7 @@
|
||||
package com.micro.fast.security.core.validate.code.config.param;
|
||||
|
||||
import com.micro.fast.security.core.master.SecurityConstants;
|
||||
|
||||
/**
|
||||
* @author lsy
|
||||
*/
|
||||
@@ -16,7 +18,7 @@ public class SmsCodeProperties {
|
||||
/**
|
||||
* 需要进行验证码校验的url
|
||||
*/
|
||||
private String url = "/user/login";
|
||||
private String url = SecurityConstants.MOBILE_LOGIN_PROCESSOR_URI;
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
package com.micro.fast.security.core.validate.code.controller;
|
||||
|
||||
import com.micro.fast.security.core.master.SecurityConstants;
|
||||
import com.micro.fast.security.core.validate.code.processor.ValidateCodeProcessor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.ServletRequestBindingException;
|
||||
@@ -29,7 +30,7 @@ public class ValidateCodeController {
|
||||
|
||||
private static final String VALIDATE_CODE_PROCESSOR_SUFFIX = "ValidateCodeProcessor";
|
||||
|
||||
@GetMapping("/code/{type}")
|
||||
@GetMapping(SecurityConstants.GET_VALIDATE_CODE_PREFIX+"{type}")
|
||||
public void createCode(HttpServletResponse response, HttpServletRequest request,@PathVariable("type") String type) throws IOException, ServletRequestBindingException {
|
||||
//create save send ValidateCode
|
||||
validateCodeProcessors.get(type+VALIDATE_CODE_PROCESSOR_SUFFIX).create(new ServletWebRequest(request,response));
|
||||
|
||||
-132
@@ -1,132 +0,0 @@
|
||||
package com.micro.fast.security.core.validate.code.filter;
|
||||
|
||||
import com.micro.fast.security.core.authentication.mobile.SmsCodeAuthenticationFilter;
|
||||
import com.micro.fast.security.core.master.SecurityProperties;
|
||||
import com.micro.fast.security.core.validate.code.exception.ValidateCodeException;
|
||||
import com.micro.fast.security.core.validate.code.pojo.ValidateCode;
|
||||
import com.micro.fast.security.core.validate.code.processor.ValidateCodeProcessor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.social.connect.web.HttpSessionSessionStrategy;
|
||||
import org.springframework.social.connect.web.SessionStrategy;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
public class SmsValidateCodeFilter extends OncePerRequestFilter implements InitializingBean {
|
||||
private AuthenticationFailureHandler authenticationFailureHandler;
|
||||
/**
|
||||
* session操作工具类
|
||||
*/
|
||||
private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
|
||||
|
||||
private SecurityProperties securityProperties;
|
||||
|
||||
private Set<String> filterUrl = new HashSet<String>();
|
||||
|
||||
private static final String REQUEST_METHOD = "post";
|
||||
|
||||
/**
|
||||
* 初始化filter url
|
||||
* @throws ServletException
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws ServletException {
|
||||
super.afterPropertiesSet();
|
||||
String url = securityProperties.getCode().getSms().getUrl();
|
||||
String[] urls = url.split(",");
|
||||
for (String s : urls) {
|
||||
filterUrl.add(s);
|
||||
}
|
||||
filterUrl.add(SmsCodeAuthenticationFilter.AUTHENTICATION_MOBILE_URL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(
|
||||
HttpServletRequest httpServletRequest
|
||||
, HttpServletResponse httpServletResponse
|
||||
, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
//判断是否需要验证码校验
|
||||
boolean filter = false;
|
||||
AntPathMatcher antPathMatcher = new AntPathMatcher();
|
||||
Iterator<String> iterator = filterUrl.iterator();
|
||||
while (iterator.hasNext()){
|
||||
if (antPathMatcher.match(iterator.next(),httpServletRequest.getRequestURI())){
|
||||
filter = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//在登录post请求的时候对验证码进行校验
|
||||
if (filter && StringUtils.endsWithIgnoreCase(httpServletRequest.getMethod(),REQUEST_METHOD)){
|
||||
try{
|
||||
//校验验证码是否正确
|
||||
validate(new ServletWebRequest(httpServletRequest));
|
||||
}catch(ValidateCodeException e){
|
||||
//进行身份认证失败后的处理
|
||||
authenticationFailureHandler.onAuthenticationFailure(httpServletRequest,httpServletResponse,e);
|
||||
//身份认证失败的时候直接return返回给页面信息,不进行后续的
|
||||
return;
|
||||
}
|
||||
}
|
||||
//执行后续的过滤器
|
||||
filterChain.doFilter(httpServletRequest,httpServletResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证码校验
|
||||
* @param servletWebRequest
|
||||
*/
|
||||
private void validate(ServletWebRequest servletWebRequest) {
|
||||
ValidateCode validateCode = (ValidateCode)(sessionStrategy.getAttribute(servletWebRequest, ValidateCodeProcessor.SESSION_KEY_PREFIX+"SMS"));
|
||||
String code = servletWebRequest.getParameter("smsCode");
|
||||
//session和用户传入的验证码不能为空
|
||||
if (validateCode==null || StringUtils.isBlank(code)){
|
||||
throw new ValidateCodeException("未生成验证码对象或用户传入的验证码为空");
|
||||
}
|
||||
if (validateCode.getCode()==null
|
||||
|| !validateCode.getCode().equals(code)){
|
||||
throw new ValidateCodeException("验证码校验失败");
|
||||
}
|
||||
if (validateCode.isExpire()){
|
||||
throw new ValidateCodeException("验证码已过期");
|
||||
}
|
||||
//一次校验完成之后删除验证码
|
||||
sessionStrategy.removeAttribute(servletWebRequest,ValidateCodeProcessor.SESSION_KEY_PREFIX+"SMS");
|
||||
}
|
||||
|
||||
public AuthenticationFailureHandler getAuthenticationFailureHandler() {
|
||||
return authenticationFailureHandler;
|
||||
}
|
||||
|
||||
public void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) {
|
||||
this.authenticationFailureHandler = authenticationFailureHandler;
|
||||
}
|
||||
|
||||
public Set<String> getFilterUrl() {
|
||||
return filterUrl;
|
||||
}
|
||||
|
||||
public void setFilterUrl(Set<String> filterUrl) {
|
||||
this.filterUrl = filterUrl;
|
||||
}
|
||||
|
||||
public SecurityProperties getSecurityProperties() {
|
||||
return securityProperties;
|
||||
}
|
||||
|
||||
public void setSecurityProperties(SecurityProperties securityProperties) {
|
||||
this.securityProperties = securityProperties;
|
||||
}
|
||||
}
|
||||
+127
-94
@@ -1,5 +1,6 @@
|
||||
package com.micro.fast.security.core.validate.code.filter;
|
||||
|
||||
import com.micro.fast.security.core.master.SecurityConstants;
|
||||
import com.micro.fast.security.core.master.SecurityProperties;
|
||||
import com.micro.fast.security.core.validate.code.exception.ValidateCodeException;
|
||||
import com.micro.fast.security.core.validate.code.pojo.ValidateCode;
|
||||
@@ -18,119 +19,151 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 图片验证码校验过滤器
|
||||
*
|
||||
* @author LSY
|
||||
*/
|
||||
public class ValidateCodeFilter extends OncePerRequestFilter implements InitializingBean{
|
||||
public class ValidateCodeFilter extends OncePerRequestFilter implements InitializingBean {
|
||||
|
||||
private AuthenticationFailureHandler authenticationFailureHandler;
|
||||
/**
|
||||
* session操作工具类
|
||||
*/
|
||||
private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
|
||||
public static final String IMAGE = "IMAGE";
|
||||
public static final String SMS = "SMS";
|
||||
|
||||
private SecurityProperties securityProperties;
|
||||
private AuthenticationFailureHandler authenticationFailureHandler;
|
||||
|
||||
private Set<String> filterUrl = new HashSet<String>();
|
||||
/**
|
||||
* session操作工具类
|
||||
*/
|
||||
private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
|
||||
|
||||
private static final String REQUEST_METHOD = "post";
|
||||
private SecurityProperties securityProperties;
|
||||
|
||||
/**
|
||||
* 初始化filter url
|
||||
* @throws ServletException
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws ServletException {
|
||||
super.afterPropertiesSet();
|
||||
String url = securityProperties.getCode().getImage().getUrl();
|
||||
String[] urls = url.split(",");
|
||||
for (String s : urls) {
|
||||
filterUrl.add(s);
|
||||
}
|
||||
filterUrl.add("/user/login");
|
||||
/**
|
||||
* 需要进行验证码校验的路径和校验的类型的map
|
||||
*/
|
||||
private Map<String, String> filterUrlMap = new HashMap<>();
|
||||
|
||||
private static final String REQUEST_METHOD = "post";
|
||||
|
||||
/**
|
||||
* 初始化filterUrlMap
|
||||
*
|
||||
* @throws ServletException
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws ServletException {
|
||||
super.afterPropertiesSet();
|
||||
String imageUrl = securityProperties.getCode().getImage().getUrl();
|
||||
putValidateUrlsToMap(imageUrl, IMAGE);
|
||||
String smsUrl = securityProperties.getCode().getSms().getUrl();
|
||||
putValidateUrlsToMap(smsUrl, SMS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将需要校验的请求路径和校验类类型存入filterUrlMap中
|
||||
*
|
||||
* @param patterns
|
||||
* @param type
|
||||
*/
|
||||
private void putValidateUrlsToMap(String patterns, String type) {
|
||||
String[] urls = patterns.split(",");
|
||||
for (String url : urls) {
|
||||
filterUrlMap.put(url, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(
|
||||
HttpServletRequest httpServletRequest
|
||||
, HttpServletResponse httpServletResponse
|
||||
, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
//判断是否需要验证码校验
|
||||
boolean filter = false;
|
||||
AntPathMatcher antPathMatcher = new AntPathMatcher();
|
||||
Iterator<String> iterator = filterUrl.iterator();
|
||||
while (iterator.hasNext()){
|
||||
if (antPathMatcher.match(iterator.next(),httpServletRequest.getRequestURI())){
|
||||
filter = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//在登录post请求的时候对验证码进行校验
|
||||
if (filter && StringUtils.endsWithIgnoreCase(httpServletRequest.getMethod(),REQUEST_METHOD)){
|
||||
try{
|
||||
//校验验证码是否正确
|
||||
validate(new ServletWebRequest(httpServletRequest));
|
||||
}catch(ValidateCodeException e){
|
||||
//进行身份认证失败后的处理
|
||||
authenticationFailureHandler.onAuthenticationFailure(httpServletRequest,httpServletResponse,e);
|
||||
//身份认证失败的时候直接return返回给页面信息,不进行后续的
|
||||
return;
|
||||
}
|
||||
}
|
||||
//执行后续的过滤器
|
||||
filterChain.doFilter(httpServletRequest,httpServletResponse);
|
||||
if (IMAGE.equals(type)) {
|
||||
filterUrlMap.put(SecurityConstants.FORM_LOGIN_PROCESSOR_URI, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证码校验
|
||||
* @param servletWebRequest
|
||||
*/
|
||||
private void validate(ServletWebRequest servletWebRequest) {
|
||||
ValidateCode validateCode = (ValidateCode)(sessionStrategy.getAttribute(servletWebRequest, ValidateCodeProcessor.SESSION_KEY_PREFIX+"IMAGE"));
|
||||
String code = servletWebRequest.getParameter("imageCode");
|
||||
//session和用户传入的验证码不能为空
|
||||
if (validateCode==null || StringUtils.isBlank(code)){
|
||||
throw new ValidateCodeException("未生成验证码对象或用户传入的验证码为空");
|
||||
}
|
||||
if (validateCode.getCode()==null
|
||||
|| !validateCode.getCode().equals(code)){
|
||||
throw new ValidateCodeException("验证码校验失败");
|
||||
}
|
||||
if (validateCode.isExpire()){
|
||||
throw new ValidateCodeException("验证码已过期");
|
||||
}
|
||||
//一次校验完成之后删除验证码
|
||||
sessionStrategy.removeAttribute(servletWebRequest,ValidateCodeProcessor.SESSION_KEY_PREFIX+"IMAGE");
|
||||
if (SMS.equals(type)) {
|
||||
filterUrlMap.put(SecurityConstants.MOBILE_LOGIN_PROCESSOR_URI, type);
|
||||
}
|
||||
}
|
||||
|
||||
public AuthenticationFailureHandler getAuthenticationFailureHandler() {
|
||||
return authenticationFailureHandler;
|
||||
}
|
||||
@Override
|
||||
protected void doFilterInternal(
|
||||
HttpServletRequest httpServletRequest
|
||||
, HttpServletResponse httpServletResponse
|
||||
, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
public void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) {
|
||||
this.authenticationFailureHandler = authenticationFailureHandler;
|
||||
//判断是否需要验证码校验
|
||||
boolean filter = false;
|
||||
//进行校验的类型
|
||||
String validateType = "";
|
||||
AntPathMatcher antPathMatcher = new AntPathMatcher();
|
||||
Set<String> filterUrls = filterUrlMap.keySet();
|
||||
Iterator<String> iterator = filterUrls.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
String next = iterator.next();
|
||||
if (antPathMatcher.match(next, httpServletRequest.getRequestURI())) {
|
||||
filter = true;
|
||||
validateType = filterUrlMap.get(next);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//在登录post请求的时候对验证码进行校验
|
||||
if (filter && StringUtils.endsWithIgnoreCase(httpServletRequest.getMethod(), REQUEST_METHOD)) {
|
||||
try {
|
||||
//校验验证码是否正确
|
||||
validate(new ServletWebRequest(httpServletRequest),validateType);
|
||||
} catch (ValidateCodeException e) {
|
||||
//进行身份认证失败后的处理
|
||||
authenticationFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, e);
|
||||
//身份认证失败的时候直接return返回给页面信息,不进行后续的
|
||||
return;
|
||||
}
|
||||
}
|
||||
//执行后续的过滤器
|
||||
filterChain.doFilter(httpServletRequest, httpServletResponse);
|
||||
}
|
||||
|
||||
public Set<String> getFilterUrl() {
|
||||
return filterUrl;
|
||||
}
|
||||
/**
|
||||
* 验证码校验
|
||||
*
|
||||
* @param servletWebRequest
|
||||
* @param validateType
|
||||
*/
|
||||
private void validate(ServletWebRequest servletWebRequest, String validateType) {
|
||||
ValidateCode validateCode = (ValidateCode) (sessionStrategy.getAttribute(servletWebRequest, ValidateCodeProcessor.SESSION_KEY_PREFIX + validateType));
|
||||
String code = servletWebRequest.getParameter(validateType.toLowerCase()+"Code");
|
||||
|
||||
public void setFilterUrl(Set<String> filterUrl) {
|
||||
this.filterUrl = filterUrl;
|
||||
//session和用户传入的验证码不能为空
|
||||
if (validateCode == null || StringUtils.isBlank(code)) {
|
||||
throw new ValidateCodeException("未生成验证码对象或用户传入的验证码为空");
|
||||
}
|
||||
if (validateCode.getCode() == null
|
||||
|| !validateCode.getCode().equals(code)) {
|
||||
throw new ValidateCodeException("验证码校验失败");
|
||||
}
|
||||
if (validateCode.isExpire()) {
|
||||
throw new ValidateCodeException("验证码已过期");
|
||||
}
|
||||
//一次校验完成之后删除验证码
|
||||
sessionStrategy.removeAttribute(servletWebRequest, ValidateCodeProcessor.SESSION_KEY_PREFIX + validateType);
|
||||
}
|
||||
|
||||
public SecurityProperties getSecurityProperties() {
|
||||
return securityProperties;
|
||||
}
|
||||
public AuthenticationFailureHandler getAuthenticationFailureHandler() {
|
||||
return authenticationFailureHandler;
|
||||
}
|
||||
|
||||
public void setSecurityProperties(SecurityProperties securityProperties) {
|
||||
this.securityProperties = securityProperties;
|
||||
}
|
||||
public void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) {
|
||||
this.authenticationFailureHandler = authenticationFailureHandler;
|
||||
}
|
||||
|
||||
public Map<String, String> getFilterUrlMap() {
|
||||
return filterUrlMap;
|
||||
}
|
||||
|
||||
public void setFilterUrlMap(Map<String, String> filterUrlMap) {
|
||||
this.filterUrlMap = filterUrlMap;
|
||||
}
|
||||
|
||||
public SecurityProperties getSecurityProperties() {
|
||||
return securityProperties;
|
||||
}
|
||||
|
||||
public void setSecurityProperties(SecurityProperties securityProperties) {
|
||||
this.securityProperties = securityProperties;
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -16,6 +16,7 @@ public interface ValidateCodeProcessor {
|
||||
*/
|
||||
String SESSION_KEY_PREFIX = "SESSION_KEY_FOR_CODE_";
|
||||
|
||||
|
||||
/**
|
||||
* 创建验证码,将验证码写入session中,输出验证码
|
||||
* @param servletWebRequest 封装请求和响应
|
||||
|
||||
+2
-3
@@ -1,5 +1,6 @@
|
||||
package com.micro.fast.security.core.validate.code.processor.impl;
|
||||
|
||||
import com.micro.fast.security.core.master.SecurityConstants;
|
||||
import com.micro.fast.security.core.validate.code.pojo.ValidateCode;
|
||||
import com.micro.fast.security.core.validate.code.service.SendSmsCode;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -17,12 +18,10 @@ public class SmsValidateCodeProcessor extends AbstractValidateCodeProcessor{
|
||||
@Autowired
|
||||
private SendSmsCode sendSmsCode;
|
||||
|
||||
private static final String PHONE = "phone";
|
||||
|
||||
@Override
|
||||
public void send(ServletWebRequest servletWebRequest, ValidateCode validateCode) throws ServletRequestBindingException {
|
||||
//获取phone,请求中必须包含用户的手机号
|
||||
String phone = ServletRequestUtils.getRequiredStringParameter(servletWebRequest.getRequest(), PHONE);
|
||||
String phone = ServletRequestUtils.getRequiredStringParameter(servletWebRequest.getRequest(), SecurityConstants.MOBILE_LOGIN_PROCESSOR_PARAM_MOBILE_KEY);
|
||||
//发送验证码的逻辑
|
||||
sendSmsCode.sendCode(phone,validateCode.getCode());
|
||||
}
|
||||
|
||||
+4
-1
@@ -6,9 +6,12 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
||||
|
||||
/**
|
||||
* swagger文档的默认的访问地址是/swagger-ui.html
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@RestController
|
||||
@EnableSwagger2//默认的访问地址是/swagger-ui.html
|
||||
@EnableSwagger2
|
||||
public class BootStarterSecurityDemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
+8
-2
@@ -12,8 +12,14 @@ import org.springframework.cloud.config.server.EnableConfigServer;
|
||||
* @since 1.0
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableConfigServer //开启配置中心相关服务
|
||||
@EnableDiscoveryClient//允许注册到注册中心
|
||||
/**
|
||||
* 开启配置中心相关服务
|
||||
*/
|
||||
@EnableConfigServer
|
||||
/**
|
||||
* 允许注册到注册中心
|
||||
*/
|
||||
@EnableDiscoveryClient
|
||||
public class ConfigServerApplication {
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<root>
|
||||
<item name='org.springframework.security.authentication.AuthenticationManager'>
|
||||
<annotation name='java.lang.Deprecated'/>
|
||||
</item>
|
||||
</root>
|
||||
Reference in New Issue
Block a user