- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Spring Security基于自定义的认证提供器实现图形验证码流程解析由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
在上一个章节中,一一哥 带大家实现了如何在Spring Security中添加执行自定义的过滤器,进而实现验证码校验功能。这种实现方式,只是实现验证码功能的方式之一,接下来我们再学习另一种实现方式,就是利用AuthenticationProver来实现验证码功能,通过这个案例,我们学习如何进行自定义AuthenticationProver.
。
在上一章节中,我带各位利用自定义的过滤器实现了图形验证码效果,接下来我们利用另一种方式,基于自定义的认证提供器来实现图形验证码.
在第11章节中,壹哥 给大家讲过Spring Security的认证授权实现流程,其中就给大家讲解过AuthenticationProver的作用,接下来我们看一下AuthenticationProver接口的类关系图:
从上图中可知,AuthenticationProver是一个接口,该接口有一个直接的子类AbstractUserDetailsAuthenticationProver,该类有2个抽象的方法:additionalAuthenticationChecks() 和 retrieveUser(),如下图:
我们可以通过编写一个子类继承AbstractUserDetailsAuthenticationProver,复写这2个抽象方法,进行满足自己需求的扩展实现。Spring Security中的DaoAuthenticationProver子类就是通过复写这2个抽象方法,实现了基于数据库模型的认证授权.
我们今天会通过继承DaoAuthenticationProver,来实现图形验证码的校验功能.
了解完上面的AuthenticationProver类之后,我们还需要了解另一个类WebAuthenticationDetails.
我们知道在Spring Security中有一个UsernamePasswordAuthenticationToken类,封装了用户的principal、credentials信息,该类还从它的父类AbstractAuthenticationToken中继承了details信息。其中这个details信息表示认证用户的额外信息,比如请求用户的remoteAddress和sessionId等信息,这两个信息都是在另一个WebAuthenticationDetails类中定义的,所以我们可以利用WebAuthenticationDetails来封装用户的额外信息.
了解完上面的这些必要的API,我们就可以实现今天的需求了.
。
我们还是和之前的案例一样,可以先创建一个新的module,创建过程略.
在本案例中我们依然采用github上的开源验证码解决方案kaptcha,所以需要在原有项目的基础上添加kaptcha的依赖包.
<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>
跟上一个案例一样,创建CaptchaConfig配置类,在该类中创建一个Producer对象,对验证码对象进行必要的配置.
@Configurationpublic class CaptchaConfig { @Bean public Producer captcha() { // 配置图形验证码的基本参数 Properties properties = new Properties(); // 图片宽度 properties.setProperty("kaptcha.image.wth", "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; }}
在上面创建了Producer对象后,接着创建一个生成验证码的接口,该接口中负责生成验证码图片,并将验证码存储到session中.
@Controllerpublic class CaptchaController { @Autowired private Producer captchaProducer; @GetMapping("/captcha.jpg") public vo 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(); } }}
接下来自定义一个运行时异常,用于处理验证码校验失败时抛出异常提示信息.
public class VerificationCodeException extends AuthenticationException { public VerificationCodeException() { super("图形验证码校验失败"); }}
我在上面给大家介绍过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"); } }}
AuthenticationDetailsSource是一个接口,该接口带有一个buildDetails方法,该方法会在创建一个新的authentication的details对象时被调用,而且可以在这里传递给details对象一个request参数,如下图所示:
所以这里我们定义一个AuthenticationDetailsSource类,通过该类构建出上面定义的WebAuthenticationDetails对象,并且给WebAuthenticationDetails传递进去HttpServletRequest对象.
@Componentpublic class MyWebAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest,WebAuthenticationDetails> { /** * 创建一个WebAuthenticationDetails对象 */ @Overre public WebAuthenticationDetails buildDetails(HttpServletRequest request) { return new MyWebAuthenticationDetails(request); }}
接下来通过继承DaoAuthenticationProver父类,来引入对图形验证码的验证操作.
/*** 在常规的数据库认证之上,添加图形验证码功能*/@Componentpublic class MyAuthenticationProver extends DaoAuthenticationProver { /** * 构造方法注入UserDetailService和PasswordEncoder */ public MyAuthenticationProver(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) { this.setUserDetailsService(userDetailsService); this.setPasswordEncoder(passwordEncoder); } /** * 在常规的认证之上,添加额外的图形验证码功能 */ @Overre protected vo additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException { //获取token令牌中关联的details对象,并将其转换为我们自定义的MyWebAuthenticationDetails MyWebAuthenticationDetails details = (MyWebAuthenticationDetails) usernamePasswordAuthenticationToken.getDetails(); String imageCode = details.getImageCode(); String savedImageCode = details.getSavedImageCode(); // 检验图形验证码 if (StringUtils.isEmpty(imageCode) || StringUtils.isEmpty(savedImageCode) || !imageCode.equals(savedImageCode)) { throw new VerificationCodeException(); } //在正常的认证检查之前,添加额外的关于图形验证码的校验 super.additionalAuthenticationChecks(userDetails, usernamePasswordAuthenticationToken); }}
然后创建编写SecurityConfig类,关联配置我们前面编写的AuthenticationDetailsSource和AuthenticationProver类.
@SuppressWarnings("all")@EnableWebSecurity(debug = true)public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> myWebAuthenticationDetailsSource; @Autowired private AuthenticationProver authenticationProver; @Overre protected vo configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin/api/**") .hasRole("ADMIN") .antMatchers("/user/api/**") .hasRole("USER") .antMatchers("/app/api/**", "/captcha.jpg") .permitAll() .anyRequest() .authenticated() .and() .formLogin() //这里关联配置自定义的AuthenticationDetailsSource .authenticationDetailsSource(myWebAuthenticationDetailsSource) .failureHandler(new SecurityAuthenticationFailureHandler()) .successHandler(new SecurityAuthenticationSuccessHandler()) .loginPage("/myLogin.html") .loginProcessingUrl("/login") .permitAll() .and() .csrf() .disable(); } //在这里关联我们自定义的AuthenticationProver @Overre protected vo configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProver(authenticationProver); } @Bean public PasswordEncoder passwordEncoder() { return NoOpPasswordEncoder.getInstance(); }}
最后编写一个自定义的登录页面,在这里添加对验证码接口的引用,我这里列出html的核心代码.
<body> <div class="login"> <h2>Access Form</h2> <div class="login-top"> <h1>登录验证</h1> <form action="/login" method="post"> <input type="text" name="username" placeholder="username" /> <input type="password" name="password" placeholder="password" /> <div style="display: flex;"> <!-- 新增图形验证码的输入框 --> <input type="text" name="captcha" placeholder="captcha" /> <!-- 图片指向图形验证码API --> <img src="/captcha.jpg" </div> <div class="forgot"> <a href="#" rel="external nofollow" rel="external nofollow" >忘记密码</a> <input type="submit" value="登录" > </div> </form> </div> <div class="login-bottom"> <h3>新用户 <a href="#" rel="external nofollow" rel="external nofollow" >注 册</a></h3> </div> </div> </body>
本案例的主要代码结构如下图所示,各位可以参考创建.
接下来我们启动项目,跳转到登录页面后,我们就可以看到验证码已经被创建出来了.
此时我们可以看到生成的数字验证码,在我们输入正确的用户名、密码、验证码后,就可以成功的登录进去访问web接口了.
至此,我们就实现了基于自定义的认证提供器来实现图形验证码功能了,这种实现方式要比第一种实现方式更复杂一些,其实都能满足我们的开发需求。有的小伙伴会问,开发时到底选择哪一种方式呢?壹哥觉得都无所谓的!你有什么更好的见解吗?可以在评论区留言哦! 。
到此这篇关于Spring Security基于自定义的认证提供器实现图形验证码的文章就介绍到这了,更多相关Spring Security认证提供器实现图形验证码内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://blog.csdn.net/syc000666/article/details/120481562 。
最后此篇关于Spring Security基于自定义的认证提供器实现图形验证码流程解析的文章就讲到这里了,如果你想了解更多关于Spring Security基于自定义的认证提供器实现图形验证码流程解析的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我一直在为此而苦苦挣扎。我想插入一个图像,并将其“靠近”讨论该图像的文本,但是该页面上的文本将围绕图像环绕/流动。 我已将图像转换为eps格式。最初,我尝试使用图形环境(\begin {figure}
我在用户界面中创建了管理控制台,管理员可以在其中执行所有操作,例如创建、删除用户、向用户分配应用程序以及从用户界面删除用户的应用程序访问权限 我厌倦了使用 Microsoft 图形 API 和 Azu
我在用户界面中创建了管理控制台,管理员可以在其中执行所有操作,例如创建、删除用户、向用户分配应用程序以及从用户界面删除用户的应用程序访问权限 我厌倦了使用 Microsoft 图形 API 和 Azu
我想为计算机图形学类(class)做一个有趣的项目。我知道那里有很多文献(即 SIGGRAPH session 论文)。我对计算机图形学(即图像处理、3D 建模、渲染、动画)兴趣广泛。但是,我只学了
我试图在 MaterializeCSS 网站上创建一些类似于这个的图形,但我不知道它来自哪里,我查看了整个 MaterializeCSS 网站,它不是框架的一部分,我找不到在代码中他们使用的是什么 我
我有一个包含 1 到 6 之间的各种数字的 TextView ,每个数字在每一行上代表一次,例如 123456 213456 214356 ...... 我希望能够绘制一条蓝线来跟随单个数值在列表中向
我目前在 Windows 7 上使用 Netbeans 和 Cygwin,我希望用 C 语言编写一个简单的 2D 游戏。 我设法找到的大多数教程都使用 Turbo C 提供的 graphics.h,C
亲爱的,我正在尝试将 kaggle 教程代码应用于 Iris 数据集。 不幸的是,当我执行图表的代码时,我只能看到这个输出而看不到任何图表: matplotlib.axes._subplots.Axe
我需要加快我正在处理的一些粒子系统的视觉效果。令人眼前一亮的是添加混合、积累以及粒子上的轨迹和发光。目前我正在手动渲染到浮点图像缓冲区,在最后一分钟转换为无符号字符,然后上传到 OpenGL 纹理。为
在研究跨网络的最短路径算法时,我想生成网络图片。我想代表节点(圆圈)、链接(线)、遍历链接的成本(链接线中间的数字)和链接的容量(链接线上它代表的节点旁边的数字)在这张图中。是否有任何库/软件可以帮助
尽管我已将应用程序从库添加到 Azure AD,但我无法看到何时尝试提取数据。但我可以看到添加的自定义应用程序。就像我添加了 7 个应用程序一样; 2 个来自图库(Google 文档、一个驱动器)和
因此,我正在构建一个系统,该系统具有“人员”,“银行帐户”和“银行帐户交易”。 我需要能够回答以下问题: “将所有与1/2/3度有联系的人归还给特定的人”, “返回年龄在40岁以上的所有人” “从德国
我在 JFrame 构造函数中有以下简单代码 super(name); setBounds(0,0,1100,750); setLayout(null); setVis
(这是java)我有一个椭圆形,代表一个单位。我希望椭圆形的颜色代表单位的健康状况。因此,一个完全健康的单位将是全绿色的。随着单位生命值的降低,椭圆形开始从底部填充红色。因此,在 50% 生命值下,椭
我目前正在开发一个学校项目。我们必须制作一个Applet,我选择了JApplet。由于某种原因,我用来显示特定字符串的面板将不会显示。这里可能有什么问题?请指出我正确的方向。另外,我看了一些教程,
我正在尝试创建一个 Simon game 。我正在编写游戏程序,但遇到了问题。我希望程序从队列中读取游戏中之前存在的所有值,并以正确的顺序将它们的颜色变为闪烁(我选择将它们变为灰色,然后在第二秒后恢复
我正在尝试创建一个框架,该框架在同一框架的顶部有一个图形面板(通过布局),在其下方有一个按钮/标签面板。到目前为止,我似乎已经能够将它们放在同一个框架上,但与按钮/标签面板相比,图形面板非常小....
我用 Java 编写了一个解决数独问题的代码,并使用 Java Applet 来设计它。现在,我尝试使用 Java Swing 使其看起来更好,并添加一些功能,例如“保存”数独板等。不幸的是,我对 J
就目前情况而言,这个问题不太适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、民意调查或扩展讨论。如果您觉得这个问题可以改进并可能重新开放,visit
我现在尝试了 8 个多小时来解决这个问题,但无法弄清楚,请帮助找出我的代码有什么问题。 int main() { int gd = DETECT, gm; float ANGLE =
我是一名优秀的程序员,十分优秀!