晚上短信验证码功能开发

This commit is contained in:
winLsy
2017-12-15 21:36:08 +08:00
parent 8cc1080725
commit d6f942003c
13 changed files with 115 additions and 62 deletions
@@ -3,9 +3,10 @@
##相关配置参数说明
- `ms.security.browser.html` 自定义登录页面的地址
- `ms.security.browser.loginType` 身份认证后响应类型`REDIRECT`页面形式响应
- `ms.security.browser.rememberMeSeconds` 记住我的时间,单位是秒。默认的时间是3600秒
`JSON` json形式的响应
- `ms.security.browser.rememberMeSeconds` 记住我的时间,单位是秒,默认的时间是3600秒
`JSON`, json形式的响应
- 定义自己的根据用户名获取密码的bean,定义自己的bean的名字为`userServiceImpl`即可
- `/authentication/require`处理身份认证跳转的接口地址
- 需要注入`userServiceImpl`获取用户详细信息的bean
- 需要注入数据源`masterDataSource`用于记住我功能的bean
- 需要注入数据源`masterDataSource`用于记住我功能的bean,记住我功能需要在登录的时候传入
`remember-me`参数,值为`true`
@@ -79,28 +79,44 @@ public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
validateCodeFilter.setSecurityProperties(securityProperties);
validateCodeFilter.afterPropertiesSet();
http
.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)//添加自定义的验证码处理器,在用户密码校验过滤器之前
.formLogin()//使用表单登录
.loginPage("/authentication/require")//自定义登录页面
.loginProcessingUrl("/user/login")//配置spring security登录接口的访问地址,用于在自定义的登录页面提交请求
.successHandler(msAuthenticationSuccessHandler)//定义身份认证成功后处理对象
.failureHandler(msAuthenticationFailureHandler)//定义身份认证失败后处理对象
//添加自定义的验证码处理器,在用户密码校验过滤器之前
.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
//使用表单登录
.formLogin()
//自定义登录页面
.loginPage("/authentication/require")
//配置spring security登录接口的访问地址,用于在自定义的登录页面提交请求
.loginProcessingUrl("/user/login")
//定义身份认证成功后处理对象
.successHandler(msAuthenticationSuccessHandler)
//定义身份认证失败后处理对象
.failureHandler(msAuthenticationFailureHandler)
.and()
//记住我功能的相关配置
.rememberMe()
.tokenRepository(persistentTokenRepository())//设置token的存储方式
.tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())//设置过期秒数
.userDetailsService(userDetailsService)//设置获取用户信息后登录的方式
//设置token的存储方式
.tokenRepository(persistentTokenRepository())
//设置过期秒数
.tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())
//设置获取用户信息后登录的方式
.userDetailsService(userDetailsService)
.and()
.authorizeRequests()//下面是权限配置
.antMatchers("/user/login", "/code/*", "/authentication/require", securityProperties.getBrowser().getHtml()).permitAll()//当访问这个页面的时候不进行身份认证,对用户自定义的登录页也不进行权限认证
.anyRequest()//任何请求
.authenticated()//都需要身份认证
//当访问这个页面的时候不进行身份认证,对用户自定义的登录页也不进行权限认证
.antMatchers("/user/login", "/code/*", "/authentication/require", securityProperties.getBrowser().getHtml()).permitAll()
//任何请求
.anyRequest()
//都需要身份认证
.authenticated()
.and()
.csrf().disable();//暂时关闭掉跨站请求攻击防护
//暂时关闭掉跨站请求攻击防护
.csrf().disable();
}
/**
* 定义身份认证红密码的加密解密类的bean
*
* @return
*/
@Bean
@@ -108,6 +124,11 @@ public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
return new BCryptPasswordEncoder();
}
/**
* 用于记住我功能
*
* @return
*/
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
@@ -9,7 +9,14 @@
- `ms.security.code.image.height`图片验证码高度,默认值是`23` 可以在请求中使用`height`参数设置
- `ms.security.code.image.length`图片验证码的code长度,默认是`4` 不能在请求中设置
- `ms.security.code.image.expireIn` 图片验证码的有效时间`60`秒 不能在请求中设置
- `ms.security.code.image.url` 需要进行验证码校验的地址,默认值是`/user/login` 可以是`/user/*`这种格式,多个适用,号分割 不能在请求中设置
- 本着增量开发的原则,可以实现`imageCodeUtil`生成验证码的方法,并定义名称为`validateCodeUtil`的bean便可替换原有的验证码的生成逻辑
- 短信验证码获取接口url`/code/sms` 短信验证码
- `ms.security.code.image.url` 需要进行验证码校验的地址,默认值是`/user/login` 可以是`/user/*`这种格式,多个适用,号分割
不能在请求中设置
- 本着增量开发的原则,可以实现`imageCodeUtil`生成验证码的方法,并定义名称为`imageCodeUtil`的bean便可替换原有的图片验证码
的生成逻辑
- 短信验证码获取接口url`/code/sms` 
- `ms.security.code.sms.length` 短信验证码code的长度,默认值是`6`,不能在请求中设置
- `ms.security.code.sms.expireIn` 短信验证码的默认有效时间是`60`秒,不能在请求中设置
- `ms.security.code.sms.url`短信验证码进行耀眼的地址,默认值是`/user/login`,可以是`/user/*`这种格式,多个适用,号分割,不
能在请求中设置
- 同样的,可以实现`validateCode`生成验证码的方法,并定义名称为`smsCodeUtil`的bean便可替换原有的短信验证码的生成逻辑
@@ -29,18 +29,6 @@ import java.util.Map;
@RestController
public class ValidateCodeController {
@Autowired
private SecurityProperties securityProperties;
@Autowired
private ValidateCodeUtil imageCodeUtil;
@Autowired
private ValidateCodeUtil smsCodeUtil;
@Autowired
private SendSmsCode sendSmsCode;
/**
* Collect all objects that implement {@link ValidateCodeProcessor} interface
* 收集所有实现了{@link ValidateCodeProcessor} 接口的类
@@ -48,29 +36,12 @@ public class ValidateCodeController {
@Autowired
private Map<String,ValidateCodeProcessor> validateCodeProcessors;
private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
private static final String VALIDATE_CODE_PROCESSOR_SUFFIX = "ValidateCodeProcessor";
@GetMapping("/code/{type}")
public void createCode(HttpServletResponse response, HttpServletRequest request,@PathVariable("type") String type) throws IOException {
public void createCode(HttpServletResponse response, HttpServletRequest request,@PathVariable("type") String type) throws IOException, ServletRequestBindingException {
//create save send ValidateCode
validateCodeProcessors.get(type+"ValidateCodeProcessor").create(new ServletWebRequest(request,response));
ImageCode imageCode = (ImageCode) imageCodeUtil.createValidateCode(new ServletWebRequest(request));
ValidateCode validateCode = new ValidateCode(imageCode.getCode(),imageCode.getExpireTime());
//将验证码对象写入session中
sessionStrategy.setAttribute(new ServletWebRequest(request), ValidateCodeConst.SESSION_KEY_IMAGE_CODE,validateCode);
//将验证码写入到响应之中
ImageIO.write(imageCode.getImage(),"JPEG",response.getOutputStream());
}
@GetMapping("/code/sms")
public void createSmsCode(HttpServletResponse response, HttpServletRequest request) throws IOException, ServletRequestBindingException {
ValidateCode validateCode = smsCodeUtil.createValidateCode(new ServletWebRequest(request));
//将验证码对象写入session中
sessionStrategy.setAttribute(new ServletWebRequest(request), ValidateCodeConst.SESSION_KEY_IMAGE_CODE,validateCode);
//获取phone,请求中必须包含用户的手机号
String phone = ServletRequestUtils.getRequiredStringParameter(request, "phone");
//发送验证码的逻辑
sendSmsCode.sendCode(phone,validateCode.getCode());
validateCodeProcessors.get(type+VALIDATE_CODE_PROCESSOR_SUFFIX).create(new ServletWebRequest(request,response));
}
}
@@ -4,6 +4,7 @@ import org.springframework.security.core.AuthenticationException;
/**
* 验证码校验异常,继承自AuthenticationException对象
* @author lsy
*/
public class ValidateCodeException extends AuthenticationException {
@@ -38,6 +38,8 @@ public class ValidateCodeFilter extends OncePerRequestFilter implements Initial
private Set<String> filterUrl = new HashSet<String>();
private static final String REQUEST_METHOD = "post";
/**
* 初始化filter url
* @throws ServletException
@@ -71,7 +73,7 @@ public class ValidateCodeFilter extends OncePerRequestFilter implements Initial
}
}
//在登录post请求的时候对验证码进行校验
if (filter && StringUtils.endsWithIgnoreCase(httpServletRequest.getMethod(),"post")){
if (filter && StringUtils.endsWithIgnoreCase(httpServletRequest.getMethod(),REQUEST_METHOD)){
try{
//校验验证码是否正确
validate(new ServletWebRequest(httpServletRequest));
@@ -1,9 +1,13 @@
package com.micro.fast.security.core.validate.code.processor;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.context.request.ServletWebRequest;
import java.io.IOException;
/**
* 验证码校验controller中需要执行操作的抽象接口
* @author lsy
*/
public interface ValidateCodeProcessor {
@@ -15,7 +19,9 @@ public interface ValidateCodeProcessor {
/**
* 创建验证码,将验证码写入session中,输出验证码
* @param servletWebRequest 封装请求和响应
* @throws IOException
* @throws ServletRequestBindingException
*/
void create(ServletWebRequest servletWebRequest);
void create(ServletWebRequest servletWebRequest) throws ServletRequestBindingException, IOException;
}
@@ -7,12 +7,15 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.social.connect.web.HttpSessionSessionStrategy;
import org.springframework.social.connect.web.SessionStrategy;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.context.request.ServletWebRequest;
import java.io.IOException;
import java.util.Map;
/**
* 验证码controller中执行操作的抽象方法
* @author lsy
*/
public abstract class AbstractValidateCodeProcessor <T extends ValidateCode> implements ValidateCodeProcessor {
@@ -28,8 +31,10 @@ public abstract class AbstractValidateCodeProcessor <T extends ValidateCode> imp
@Autowired
private Map<String,ValidateCodeUtil> validateCodeUtils;
private static final String VALIDATE_CODE_UTIL_SUFFIX = "CodeUtil";
@Override
public void create(ServletWebRequest servletWebRequest) {
public void create(ServletWebRequest servletWebRequest) throws ServletRequestBindingException, IOException {
T generateCode = generateCode(servletWebRequest);
save(servletWebRequest,generateCode);
send(servletWebRequest,generateCode);
@@ -44,7 +49,7 @@ public abstract class AbstractValidateCodeProcessor <T extends ValidateCode> imp
public T generateCode(ServletWebRequest servletWebRequest){
String processorType = getProcessorType(servletWebRequest);
//根据请求的类型获取指定的验证码生成器
ValidateCodeUtil validateCodeUtil = validateCodeUtils.get(processorType + "CodeUtil");
ValidateCodeUtil validateCodeUtil = validateCodeUtils.get(processorType + VALIDATE_CODE_UTIL_SUFFIX);
return (T) validateCodeUtil.createValidateCode(servletWebRequest);
}
@@ -66,10 +71,12 @@ public abstract class AbstractValidateCodeProcessor <T extends ValidateCode> imp
/**
* 发送验证码的逻辑,延迟到子类中去实现
* @param servletWebRequest
* @param validateCode 验证码对象
* @param servletWebRequest 请求
* @param validateCode 验证码
* @throws ServletRequestBindingException 请求中不包含phone对象时抛出异常
* @throws IOException
*/
public abstract void send(ServletWebRequest servletWebRequest,T validateCode);
public abstract void send(ServletWebRequest servletWebRequest,T validateCode) throws ServletRequestBindingException, IOException;
/**
* 根据请求的url获取请求验证码的类型
@@ -1,16 +1,23 @@
package com.micro.fast.security.core.validate.code.processor.impl;
import com.micro.fast.security.core.validate.code.pojo.ImageCode;
import com.micro.fast.security.core.validate.code.pojo.ValidateCode;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.ServletWebRequest;
import javax.imageio.ImageIO;
import java.io.IOException;
/**
* 图片验证码逻辑类
* @author lsy
*/
@Component("imageValidateCodeProcessor")
public class ImageValidateCodeProcessor extends AbstractValidateCodeProcessor {
@Override
public void send(ServletWebRequest servletWebRequest, ValidateCode validateCode) {
public void send(ServletWebRequest servletWebRequest, ValidateCode validateCode) throws IOException {
ImageCode imageCode = (ImageCode)validateCode;
//将验证码写入到响应之中
ImageIO.write(imageCode.getImage(),"JPEG",servletWebRequest.getResponse().getOutputStream());
}
}
@@ -1,14 +1,29 @@
package com.micro.fast.security.core.validate.code.processor.impl;
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;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.context.request.ServletWebRequest;
/**
* @author lsy
*/
@Component("smsValidateCodeProcessor")
public class SmsValidateCodeProcessor extends AbstractValidateCodeProcessor{
@Override
public void send(ServletWebRequest servletWebRequest, ValidateCode validateCode) {
@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);
//发送验证码的逻辑
sendSmsCode.sendCode(phone,validateCode.getCode());
}
}
@@ -1,5 +1,13 @@
package com.micro.fast.security.core.validate.code.service;
/**
* @author lsy
*/
public interface SendSmsCode {
/**
* 发送短信验证码
* @param phone
* @param code
*/
void sendCode(String phone,String code);
}
@@ -12,6 +12,7 @@ import java.util.Random;
/**
* 图片验证码工具类
* @author lsy
*/
public class ImageCodeUtil implements ValidateCodeUtil{
@@ -5,7 +5,13 @@ import org.springframework.web.context.request.ServletWebRequest;
/**
* 验证码生成的接口
* @author Administrator
*/
public interface ValidateCodeUtil {
/**
* 生成验证码
* @param request 封装request和response的对象
* @return 验证码对象
*/
ValidateCode createValidateCode(ServletWebRequest request);
}