c语言sscanf函数的用法是什么
228
2023-05-18
Spring Security实现验证码登录功能
这篇文章主要介绍了Spring Security实现验证码登录功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
在spring security实现登录注销功能的基础上进行开发。
1、添加生成验证码的控制器。
(1)、生成验证码
/**
* 引入 Security 配置属性类
*/
@Autowired
private SecurityProperties securityProperties;
@Override
public ImageCode createCode(HttpServletRequest request ) {
//如果请求中有 width 参数,则用请求中的,否则用 配置属性中的
int width = ServletRequestUtils.getIntParameter(request,"width",securityProperties.getWidth());
//高度(宽度)
int height = ServletRequestUtils.getIntParameter(request,"height",securityProperties.getHeight());
//图片验证码字符个数
int length = securityProperties.getLength();
//过期时间
int expireIn = securityProperties.getExpireIn();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
Random random = new Random();
g.setColor(getRandColor(200, 250));
g.fillRect(0, 0, width, height);
g.setFont(new Font("Times New Roman", Font.ITALIC, 20));
g.setColor(getRandColor(160, 200));
for (int i = 0; i < 155; i++) {
int x = random.nextInt(width);
int y = random.nextInt(height);
int xl = random.nextInt(12);
int yl = random.nextInt(12);
g.drawLine(x, y, x + xl, y + yl);
}
String sRand = "";
for (int i = 0; i < length; i++) {
String rand = String.valueOf(random.nextInt(10));
sRand += rand;
g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
g.drawString(rand, 13 * i + 6, 16);
}
g.dispose();
return new ImageCode(image, sRand, expireIn);
}
/**
* 生成随机背景条纹
*/
private Color getRandColor(int fc, int bc) {
Random random = new Random();
if (fc > 255) {
fc = 255;
}
if (bc > 255) {
bc = 255;
}
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}
(2)、验证码控制器
public static final String SESSION_KEY = "SESSION_KEY_IMAGE_CODE";
@Autowired
private ValidateCodeGenerator imageCodeGenerator;
/**
* Session 对象
*/
private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
@GetMapping("/code/image")
public void createCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
ImageCode imageCode = imageCodeGenerator.createCode(request);
//将随机数 放到Session中
sessionStrategy.setAttribute(new ServletWebRequest(request),SESSION_KEY,imageCode);
request.getSession().setAttribute(SESSION_KEY,imageCode);
//写给response 响应
response.setHeader("Cache-Control", "no-store, no-cache");
response.setContentType("image/jpeg");
ImageIO.write(imageCode.getImage(),"JPEG",response.getOutputStream());
}
(3)、其它辅助类
@Data
public class ImageCode {
/**
* 图片
*/
private BufferedImage image;
/**
* 随机数
*/
private String code;
/**
* 过期时间
*/
private LocalDateTime expireTime;
public ImageCode(BufferedImage image, String code, LocalDateTime expireTime) {
this.image = image;
this.code = code;
this.expireTime = expireTime;
}
public ImageCode(BufferedImage image, String code, int expireIn) {
this.image = image;
this.code = code;
//当前时间 加上 设置过期的时间
this.expireTime = LocalDateTime.now().plusSeconds(expireIn);
}
public boolean isExpried(){
//如果 过期时间 在 当前日期 之前,则验证码过期
return LocalDateTime.now().isAfter(expireTime);
}
}
@ConfigurationProperties(prefix = "sso.security.code.image")
@Component
@Data
public class SecurityProperties {
/**
* 验证码宽度
*/
private int width = 67;
/**
* 高度
*/
private int height = 23;
/**
* 长度(几个数字)
*/
private int length = 4;
/**
* 过期时间
*/
private int expireIn = 60;
/**
* 需要图形验证码的 url
*/
private String url;
}
(4)、验证
2、添加过滤器,进行验证码验证
@Component
@Slf4j
public class ValidateCodeFilter extends OncePerRequestFilter implements InitializingBean {
/**
* 登录失败处理器
*/
@Autowired
private AuthenticationFailureHandler failureHandler;
/**
* Session 对象
*/
private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
/**
* 创建一个Set 集合 存放 需要验证码的 urls
*/
private Set
/**
* spring的一个工具类:用来判断 两字符串 是否匹配
*/
private AntPathMatcher pathMatcher = new AntPathMatcher();
@Autowired
private SecurityProperties securityProperties;
/**
* 这个方法是 InitializingBean 接口下的一个方法, 在初始化配置完成后 运行此方法
*/
@Override
public void afterPropertiesSet() throws ServletException {
super.afterPropertiesSet();
//将 application 配置中的 url 属性进行 切割
String[] configUrls = StringUtils.splitByWholeSeparatorPreserveAllTokens(securityProperties.getUrl(), ",");
//添加到 Set 集合里
urls.addAll(Arrays.asList(configUrls));
//因为登录请求一定要有验证码 ,所以直接 add 到set 集合中
urls.add("/authentication/form");
}
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
boolean action = false;
for (String url:urls){
//如果请求的url 和 配置中的url 相匹配
if (pathMatcher.match(url,httpServletRequest.getRequestURI())){
action = true;
}
}
//拦截请求
if (action){
logger.info("拦截成功"+httpServletRequest.getRequestURI());
//如果是登录请求
try {
validate(new ServletWebRequest(httpServletRequest));
}catch (ValidateCodeException exception){
//返回错误信息给 失败处理器
failureHandler.onAuthenticationFailure(httpServletRequest,httpServletResponse,exception);
return;
}
}
filterChain.doFilter(httpServletRequest,httpServletResponse);
}
private void validate(ServletWebRequest request) throws ServletRequestBindingException {
//从session中取出 验证码
ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(request,ValidateCodeController.SESSION_KEY);
//从request 请求中 取出 验证码
String codeInRequest = ServletRequestUtils.getStringParameter(request.getRequest(),"imageCode");
if (StringUtils.isBlank(codeInRequest)){
logger.info("验证码不能为空");
throw new ValidateCodeException("验证码不能为空");
}
if (codeInSession == null){
logger.info("验证码不存在");
throw new ValidateCodeException("验证码不存在");
}
if (codeInSession.isExpried()){
logger.info("验证码已过期");
sessionStrategy.removeAttribute(request,ValidateCodeController.SESSION_KEY);
throw new ValidateCodeException("验证码已过期");
}
if (!StringUtils.equals(codeInSession.getCode(),codeInRequest)){
logger.info("验证码不匹配"+"codeInSession:"+codeInSession.getCode() +", codeInRequest:"+codeInRequest);
throw new ValidateCodeException("验证码不匹配");
}
//把对应 的 session信息 删掉
sessionStrategy.removeAttribute(request,ValidateCodeController.SESSION_KEY);
}
3、在核心配置BrowserSecurityConfig中添加过滤器配置
@Autowired
private ValidateCodeFilter validateCodeFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
//在UsernamePasswordAuthenticationFilter 过滤器前 加一个过滤器 来搞验证码
http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
//表单登录 方式
.formLogin()
.loginPage("/authentication/require")
//登录需要经过的url请求
.loginProcessingUrl("/authentication/form")
.passwordParameter("pwd")
.usernameParameter("user")
.successHandler(mySuccessHandler)
.failureHandler(myFailHandler)
.and()
//请求授权
.authorizeRequests()
//不需要权限认证的url
.antMatchers("/authentication/*","/code/image").permitAll()
//任何请求
.anyRequest()
//需要身份认证
.authenticated()
.and()
//关闭跨站请求防护
.csrf().disable();
//默认注销地址:/logout
http.logout().
//注销之后 跳转的页面
logoutSuccessUrl("/authentication/require");
}
4、异常辅助类
public class ValidateCodeException extends AuthenticationException {
public ValidateCodeException(String msg, Throwable t) {
super(msg, t);
}
public ValidateCodeException(String msg) {
super(msg);
}
}
5、测试
(1)、不输入验证码
(2)、添加验证码
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~