爆破专栏丨Spring Security系列教程之基于自定义的认证提供器实现图形验证码_webauthenticationdetailssource

文末

我将这三次阿里面试的题目全部分专题整理出来,并附带上详细的答案解析,生成了一份PDF文档

  • 第一个要分享给大家的就是算法和数据结构

网易严选Java开发三面面经:HashMap+JVM+索引+消息队列

  • 第二个就是数据库的高频知识点与性能优化

网易严选Java开发三面面经:HashMap+JVM+索引+消息队列

  • 第三个则是并发编程(72个知识点学习)

网易严选Java开发三面面经:HashMap+JVM+索引+消息队列

  • 最后一个是各大JAVA架构专题的面试点+解析+我的一些学习的书籍资料

网易严选Java开发三面面经:HashMap+JVM+索引+消息队列

还有更多的Redis、MySQL、JVM、Kafka、微服务、Spring全家桶等学习笔记这里就不一一列举出来

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

从上图中可知,AuthenticationProvider是一个接口,该接口有一个直接的子类AbstractUserDetailsAuthenticationProvider,该类有2个抽象的方法:additionalAuthenticationChecks() 和 retrieveUser(),如下图:

图片

图片

我们可以通过编写一个子类继承Abstract User Details Authen tication Provider,复写这2个抽象方法,进行满足自己需求的扩展实现。Spring Security中的Dao Authen tication Provider子类就是通过复写这2个抽象方法,实现了基于数据库模型的认证授权。

我们今天会通过继承DaoAuthenticationProvider,来实现图形验证码的校验功能。

  1. WebAuthenticationDetails类介绍

了解完上面的AuthenticationProvider类之后,我们还需要了解另一个类WebAuthenticationDetails。

们知道在Spring Security中有一个Username Password Authen tication Token类,封装了用户的principal、credentials信息,该类还从它的父类AbstractAuthenticationToken中继承了details信息。

其中这个details信息表示认证用户的额外信息,比如请求用户的remoteAddress和sessionId等信息,这两个信息都是在另一个WebAuthenticationDetails类中定义的,所以我们可以利用WebAuthenticationDetails来封装用户的额外信息。

图片

了解完上面的这些必要的API,我们就可以实现今天的需求了。

二. 实现图形验证码

  1. 添加依赖包

我们还是和之前的案例一样,可以先创建一个新的module,创建过程略。

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>com.github.penggle</groupId>
            <artifactId>kaptcha</artifactId>
            <version>2.3.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

在本案例中我们依然采用github上的开源验证码解决方案kaptcha,所以需要在原有项目的基础上添加kaptcha的依赖包。

  1. 创建Producer对象

跟上一个案例一样,创建CaptchaConfig配置类,在该类中创建一个Producer对象,对验证码对象进行必要的配置。

@Configuration
public class CaptchaConfig {

    @Bean
    public Producer captcha() {
        // 配置图形验证码的基本参数
        Properties properties = new Properties();
        // 图片宽度
        properties.setProperty("kaptcha.image.width", "150");
        // 图片长度
        properties.setProperty("kaptcha.image.height", "50");
        // 字符集
        properties.setProperty("kaptcha.textproducer.char.string", "0123456789");
        // 字符长度
        properties.setProperty("kaptcha.textproducer.char.length", "4");
        Config config = new Config(properties);
        // 使用默认的图形验证码实现,当然也可以自定义实现
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }

}

  1. 创建生成验证码的接口

在上面创建了Producer对象后,接着创建一个生成验证码的接口,该接口中负责生成验证码图片,并将验证码存储到session中。

@Controller
public class CaptchaController {

    @Autowired
    private Producer captchaProducer;

    @GetMapping("/captcha.jpg")
    public void getCaptcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 设置内容类型
        response.setContentType("image/jpeg");
        // 创建验证码文本
        String capText = captchaProducer.createText();
        
        // 将验证码文本设置到session
        request.getSession().setAttribute("captcha", capText);
        
        // 创建验证码图片
        BufferedImage bi = captchaProducer.createImage(capText);
        // 获取响应输出流
        ServletOutputStream out = response.getOutputStream();
        // 将图片验证码数据写到响应输出流
        ImageIO.write(bi, "jpg", out);
        
        // 推送并关闭响应输出流
        try {
            out.flush();
        } finally {
            out.close();
        }
    }

}

  1. 自定义异常

接下来自定义一个运行时异常,用于处理验证码校验失败时抛出异常提示信息。

public class VerificationCodeException extends AuthenticationException {

    public VerificationCodeException() {
        super("图形验证码校验失败");
    }

}

  1. 自定义WebAuthenticationDetails

我在上面给大家介绍过WebAuthenticationDetails这个类,知道该类中可以封装用户的额外信息,所以在这里我们自定义一个WebAuthenticationDetails类,封装验证码信息,并把用户传递过来的验证码与session中保存的验证码进行对比。

/**
 * 添加额外的用户认证信息
 */  
public class MyWebAuthenticationDetails extends WebAuthenticationDetails {

    private String imageCode;

    private String savedImageCode;

    public String getImageCode() {
        return imageCode;
    }

    public String getSavedImageCode() {
        return savedImageCode;
    }

    /**
     * 补充用户提交的验证码和session保存的验证码
     */  
    public MyWebAuthenticationDetails(HttpServletRequest request) {
        super(request);
        this.imageCode = request.getParameter("captcha");
        //获取session对象
        HttpSession session = request.getSession();
        
        this.savedImageCode = (String) session.getAttribute("captcha");
        if (!StringUtils.isEmpty(this.savedImageCode)) {
            // 随手清除验证码,不管是失败还是成功,所以客户端应在登录失败时刷新验证码
            session.removeAttribute("captcha");
        }
    }

}

  1. 自定义AuthenticationDetailsSource

AuthenticationDetailsSource是一个接口,该接口带有一个buildDetails方法,该方法会在创建一个新的authentication的details对象时被调用,而且可以在这里传递给details对象一个request参数,如下图所示:

图片

所以这里我们定义一个AuthenticationDetailsSource类,通过该类构建出上面定义的WebAuthenticationDetails对象,并且给WebAuthenticationDetails传递进去HttpServletRequest对象。

@Component
public class MyWebAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest,WebAuthenticationDetails> {

    /**
     * 创建一个WebAuthenticationDetails对象
     */  
    @Override
    public WebAuthenticationDetails buildDetails(HttpServletRequest request) {

        return new MyWebAuthenticationDetails(request);
    }

}

  1. 自定义DaoAuthenticationProvider

接下来通过继承DaoAuthenticationProvider父类,来引入对图形验证码的验证操作。

/**
 * 在常规的数据库认证之上,添加图形验证码功能
 */
@Component
public class MyAuthenticationProvider extends DaoAuthenticationProvider {

    /**
     * 构造方法注入UserDetailService和PasswordEncoder


# 最后总结

## ActiveMQ+Kafka+RabbitMQ学习笔记PDF

![image.png](https://img-blog.csdnimg.cn/img_convert/e367bd5db851cca8612cf4947a1530b1.webp?x-oss-process=image/format,png)


* ### RabbitMQ实战指南

![image.png](https://img-blog.csdnimg.cn/img_convert/87b2492ae65520c28ad628b3ddcad88b.webp?x-oss-process=image/format,png)


* ### 手写RocketMQ笔记

![image.png](https://img-blog.csdnimg.cn/img_convert/9e198b456c6c4948c5967b059420d92d.webp?x-oss-process=image/format,png)


* ### 手写“Kafka笔记”

![image](https://img-blog.csdnimg.cn/img_convert/59b0b83c749f7b8b743805a4431214b6.webp?x-oss-process=image/format,png)

关于分布式,限流+缓存+缓存,这三大技术(包含:ZooKeeper+Nginx+MongoDB+memcached+Redis+ActiveMQ+Kafka+RabbitMQ)等等。这些相关的面试也好,还有手写以及学习的笔记PDF,都是啃透分布式技术必不可少的宝藏。以上的每一个专题每一个小分类都有相关的介绍,并且小编也已经将其整理成PDF啦

> **本文已被[CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)收录**

**[需要这份系统化的资料的朋友,可以点击这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**

iveMQ+Kafka+RabbitMQ)等等。这些相关的面试也好,还有手写以及学习的笔记PDF,都是啃透分布式技术必不可少的宝藏。以上的每一个专题每一个小分类都有相关的介绍,并且小编也已经将其整理成PDF啦

> **本文已被[CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)收录**

**[需要这份系统化的资料的朋友,可以点击这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**

  • 14
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值