IntelliJ+SpringBoot项目实战(十九)--在API接口中实现SpringSecurity登录并生成JWT的accessToken

        在上节中实现了SpringBoot+JWT登录,但是介绍的登录是基于SpringSecurity的默认登录页实现的。但是项目开发目前很多都是前后端分离的,也就是VUE+API接口的模式。所以我们需要实现在API接口中使用SpringSecurity登录。

        首先需要在WebSecurityConfig中增加AuthenticationManager,以便API接口类中能够引用这个AuthenticationManager:

        

    //作用:暴露AuthenticationManager给其他Bean使用@Bean@Overrideprotected AuthenticationManager authenticationManager() throws Exception {return super.authenticationManager();//return super.authenticationManagerBean();}

 如果不加这个方法的话,在API 中无法通过@AutoWired引用AuthenticationManager。

        下面我们再开发一个API接口类JwtLoginDemoApi(openjweb-sys工程里):

package org.openjweb.sys.api;import lombok.extern.slf4j.Slf4j;
import org.openjweb.core.entity.CommUser;
import org.openjweb.core.service.CommUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** 测试URL:http://localhost:8001/demo/jwt/login?loginId=admin&password=Hello0214@*/
@RestController
@RequestMapping("/demo/jwt")
@Slf4j
public class JwtLoginDemoApi {@Autowiredprivate AuthenticationManager authenticationManager; //WebSecurityConfig声明以后这里就不报红了@AutowiredCommUserService sysUserService;@RequestMapping("login")public String login(String loginId,String password){CommUser sysUser = sysUserService.selectUserByLoginId(loginId);//UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(sysUser,password);// 生成一个包含账号密码的认证信息Authentication token = new UsernamePasswordAuthenticationToken(loginId,password);Authentication authentication = authenticationManager.authenticate(token);// 将返回的Authentication存到上下文中SecurityContextHolder.getContext().setAuthentication(authentication);// CommUser user = (CommUser) authentication.getPrincipal();log.info("账号:"+user.getLoginId());return "登录成功,登录账号为:"+user.getLoginId();}
}

        启动SpringBoot,然后访问

http://localhost:8001/demo/jwt/login?loginId=admin&password=Hello0214@

        界面显示:

        在上面的程序代码中,认证成功后,通过CommUser user = (CommUser) authentication.getPrincipal();获取用户信息(CommUser是实现了UserDetails接口)。登录后,控制台显示的信息:

        看控制台的信息,在登录的时候调用了JwtAuthenticationFilter,就是上节中介绍的过滤器,但是登录成功后,并没有执行LoginSuccessHandler,我们希望在登录成功后能够通过LoginSuccessHandler加上JWT的accessToken。目前暂时没有还没找到办法能够像表单登录自动调用WebSecurityConfig中 configure(HttpSecurity http)里的各种设置,不过可以增加下面的代码调用LoginSuccessHandler:

    @AutowiredLoginSuccessHandler loginSuccessHandler;......ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();loginSuccessHandler.onAuthenticationSuccess(sra.getRequest(),sra.getResponse(),authentication);return "登录成功,登录账号为:"+user.getLoginId();......

        上面的代码就是在增加LoginSuccesshandler组件,然后认证成功后,将认证成功后的authentication交给loginSuccessHandler执行JWT封装处理,这样登录成功后,界面返回的就是上节的登录成功的JSON:{"msg":"操作成功","code":0,"data":"SuccessLogin"}

      

        如果认证失败,会返回到登录页面,现在模拟密码错误的请求:

http://localhost:8001/demo/jwt/login?loginId=admin&password=1234,界面会跳转到登录界面:

        对于前后端分离的模式,登录失败应该返回JSON接口,显然上面返回一个登录界面不是我们想要的。所以我们需要进行改造。经测试,

Authentication authentication = authenticationManager.authenticate(token);

如果认证失败,这行代码下面的代码不会执行,而是被SpringSecurity跳转了。我们再打开WebSecurityConfig.java,找到

//.authenticationEntryPoint(jwtAuthenticationEntryPoint)

去掉注释,然后在测下失败登录,界面显示{"msg":"请先登录","code":-3,"data":{}},这样就达到返回JSON错误消息的效果了。

       需要说明的是,这个EntryPoint打开后,localhost:8001/login就不管用了,显示下面的页面:

       不过因为我们反正是做前后端分离模式的开发,所以不能用反而是我们需要的。因为生产环境不会使用localhost:8001/login。不过为什么会这样后面还需要花时间研究。

        现在我们发现,当使用API接口调用登录时,WebSecurityConfig中配置是有的有效(如JwtAuthenticationFilter、还有上面的authenticationEntryPoint),但个别配置没起作用(LoginSuccessHandler),这个以后再研究。

【自定义AuthenticationProvider】

        现在介绍下如何开发自定义的AuthenticationProvider,在实际生产环境中,可能在登录的时候还需要做很多各种其他的验证,比如手机号验证,安全验证等,所以可能需要自定义AuthenticationProvider。

        我们在openjweb-sys下创建一个MyAuthenticationProvider:

package org.openjweb.sys.provider;import lombok.extern.slf4j.Slf4j;
import org.openjweb.common.util.AESUtil;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;import java.util.Collections;@Slf4j
public class MyAuthenticationProvider implements AuthenticationProvider {private UserDetailsService userDetailsService;public MyAuthenticationProvider(UserDetailsService userDetailsService) {this.userDetailsService = userDetailsService;}@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {log.info("自定义的AuthenticationProvider..................");String username = authentication.getName();String password = authentication.getCredentials().toString();UserDetails userDetails = userDetailsService.loadUserByUsername(username);//自行密码验证//将数据库中的AES密码还原String encodePwd = userDetails.getPassword();//这个KEY怎么传进来?暂时先写死String decodePwd = AESUtil.aesDncode("/Z3E1YW1mxM0BCluJdYaLHCnhTuzE8j0",encodePwd);if (userDetails == null || !password.equals(decodePwd)) {log.info("抛出异常.................");throw new BadCredentialsException("Invalid username or password");}return new UsernamePasswordAuthenticationToken(userDetails, password, Collections.emptyList());}@Overridepublic boolean supports(Class<?> authentication) {return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);}
}

        在上面的代码中,因为数据库中存储的密码是AES加密的,所以在密码比对的时候,将数据库的AES密码还原后,与前端用户传入的密码进行比较,当然可以将前端用户的密码用AES加密和数据库中加密的密码比较,另外AES加解密需要的key还没考虑如何传进来,先在代码里写死,以后再完善。

        定义了自定义的AuthenticationProvider后,需要在WebSecurityConfig中做下配置:

@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {if(false){//如果自定义AuthenticationProvider 则不使用这个auth.userDetailsService(userDetailService).passwordEncoder(aesPasswordEncoder);//auth.userDetailsService(userDetailService).passwordEncoder(new BCryptPasswordEncoder());}else{//自定义AuthenticationProviderauth.authenticationProvider(new MyAuthenticationProvider(userDetailService));}}

       上面代码中,因为使用if(false),所以执行的是自定义的Provider,如果不使用自定义的就把false改为true。

        现在我们再启动SpringBoot访问测试地址,会发现可以成功登录了。

本文总结:

       本文介绍了在API接口类中实现了SpringSecurity的用户登录,这种情况更符合现在的前后端分离的开发模式,另外介绍了认证成功后如何跳转到loginSuccessHandler从而自动进行JWT生成accessToken,以及认证失败如何返回失败的JSON,另外介绍了自定义AuthenticationProvider的开发。相信本文对做SpringSecurity API 登录的朋友能有不小的帮助。完整代码可以从Github上下载(如果大家觉得有帮助,可在GitHub上点个Star,感谢!)。

 GitHub - openjweb/cloud at masterOpenJWeb is a java bases low code platform. Contribute to openjweb/cloud development by creating an account on GitHub.icon-default.png?t=O83Ahttps://github.com/openjweb/cloud/tree/master

  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/61435.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

流水线并行,重计算:GPipe;1F1B(一前一后)调度机制

目录 GPipe 一、GPipe的背景与目的 二、GPipe的功能与特点 三、GPipe的应用与效果 四、GPipe的开源与可扩展性 1F1B(一前一后)调度机制 一、背景与基本概念 二、1F1B调度机制的要求 三、应用与挑战 GPipe 是一个基于Lingvo(Lingvo是Google基于TensorFlow二次开发的…

1-1 Gerrit实用指南

注&#xff1a;学习gerrit需要拥有git相关知识&#xff0c;如果没有学习过git请先回顾git相关知识点 黑马程序员git教程 一小时学会git git参考博客 git 实操博客 1.0 定义 Gerrit 是一个基于 Web 的代码审查系统&#xff0c;它使用 Git 作为底层版本控制系统。Gerrit 的主要功…

基于TensorFlow的手写体数字识别训练与测试

需求&#xff1a; 选择一个最简单的细分方向&#xff0c;初步了解AI图像识别的训练、测试过程TensorFlow、PyTorch、c&#xff0c;三种代码方案&#xff0c;先从TensorFlow入手探讨最基本问题的优化问题 总结&#xff1a; 基于TensorFlow的python代码库自带了mnist 训练数据…

通信与网络基础

1.网络通信基本概念 通信&#xff1a;人、物通过某种介质和行为进行信息传递与交流 网络通信&#xff1a;终端设备之间通过计算机网络进行通信 两个终端通过网线传递文件 多个终端通过路由器传递文件 终端通过Internet下载文件 2.信息传递过程 图1-1 假定A计算机访问B的web…

[免费]SpringBoot+Vue景区订票(购票)系统【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue大景区订票(购票)系统&#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue景区订票(购票)系统 Java毕业设计_哔哩哔哩_bilibili 项目介绍 现代经济快节奏发展以及不断完善升级的信息…

医疗知识图谱的问答系统详解

一、项目介绍 该项目的数据来自垂直类医疗网站寻医问药&#xff0c;使用爬虫脚本data_spider.py&#xff0c;以结构化数据为主&#xff0c;构建了以疾病为中心的医疗知识图谱&#xff0c;实体规模4.4万&#xff0c;实体关系规模30万。schema的设计根据所采集的结构化数据生成&…

【设计模式系列】解释器模式(十七)

一、什么是解释器模式 解释器模式&#xff08;Interpreter Pattern&#xff09;是一种行为型设计模式&#xff0c;它的核心思想是分离实现与解释执行。它用于定义语言的文法规则&#xff0c;并解释执行语言中的表达式。这种模式通常是将每个表达式抽象成一个类&#xff0c;并通…

AI表情神同步!LivePortrait安装配置,一键包,使用教程

快手在AI视频这领域还真有点东西&#xff0c;视频生成工具“可灵”让大家玩得不亦乐乎。 现在又开源了一个超好玩的表情同步&#xff08;表情控制&#xff09;项目。 一看这图片&#xff0c;就充满了娱乐性。发布没几天就已经有8000Star。 项目****简介 LivePortrait 是一款…

阿里云服务器(centos7.6)部署前后端分离项目

Mysql8安装部署 确定一下系统的glibc版本&#xff0c;可以使用以下命令进行查看&#xff0c;当前系统glibc版本&#xff1a;2.17&#xff08;重要&#xff01;&#xff01;&#xff01;&#xff09; 要根据自己服务器的版本去选择对应的mysql&#xff0c;不然后续安装会报错&a…

Java中TimedCache缓存对象的详细使用

一、TimedCache 是什么&#xff1f; TimedCache是一个泛型类&#xff0c;它的主要作用通常是在一定时间范围内对特定键值对进行缓存&#xff0c;并且能够根据设定的时间策略来自动清理过期的缓存项。 TimedCache是一种带有时间控制功能的缓存数据结构。在 Java 中&#xff0c…

11、数组

1、数组概念 数组就是存储多个相同数据类型的数据。 比如&#xff1a;存储26个字母&#xff0c;存储一个班级的学生成绩。 2、数组使用 数组要遵循先定义再使用 2.1、数组定义的格式 存储数据---空间 ---- 数据类型 多少个 --- 数据个数 >> 数据类型 数…

六、文本搜索工具(grep)和正则表达式

一、grep工具的使用 1、概念 grep&#xff1a; 是 linux 系统中的一个强大的文本搜索工具&#xff0c;可以按照 正则表达式 搜索文本&#xff0c;并把匹配到的行打印出来&#xff08;匹配到的内容标红&#xff09;。 2、语法 grep [options]…… pattern [file]…… 工作方式…

【python】爬去二手车数据 未完成

技术方案 python selenium 先下载Microsoft Edge WebDriver Microsoft Edge WebDriver 官网 先看一下自己的edge版本 搜索到版本然后下载自己的版本 安装依赖 pip install seleniumimport time from selenium import webdriverdriver webdriver.Edge(executable_pathr&qu…

玩游戏常常出现vc++runtime library error R6025 这是什么意思,该怎么解决?

当玩游戏时常常出现“vc runtime library error R6025”错误&#xff0c;这通常表明微软C开发运行库组件存在问题。以下是对该错误及其解决方法的详细解释&#xff1a; 错误含义 “vc runtime library error R6025”是一个与Visual C运行时库相关的错误&#xff0c;该错误表明…

【深度学习基础】一篇入门模型评估指标(分类篇)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;深度学习_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前言 2. 模…

深度学习基础02_损失函数BP算法(上)

目录 一、损失函数 1、线性回归损失函数 1.MAE损失 2.MSE损失 3.SmoothL1Loss 2、多分类损失函数--CrossEntropyLoss 3、二分类损失函数--BCELoss 4、总结 二、BP算法 1、前向传播 1.输入层(Input Layer)到隐藏层(Hidden Layer) 2.隐藏层(Hidden Layer)到输出层(Ou…

从技术视角看AI在Facebook全球化中的作用

在全球化日益加深的今天&#xff0c;人工智能&#xff08;AI&#xff09;作为一种变革性技术&#xff0c;正在深刻影响全球互联网巨头的发展方向。Facebook作为全球最大的社交媒体平台之一&#xff0c;正通过AI技术突破语言、文化和技术的障碍&#xff0c;推动全球化战略的实现…

41 基于单片机的小车行走加温湿度检测系统

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;采样DHT11温湿度传感器检测温湿度&#xff0c;滑动变阻器连接数码转换器模拟电量采集传感器&#xff0c; 电机采样L298N驱动&#xff0c;各项参数通过LCD1602显示&#x…

Python3 爬虫 Scrapy的使用

安装完成Scrapy以后&#xff0c;可以使用Scrapy自带的命令来创建一个工程模板。 一、创建项目 使用Scrapy创建工程的命令为&#xff1a; scrapy startproject <工程名> 例如&#xff0c;创建一个抓取百度的Scrapy项目&#xff0c;可以将命令写为&#xff1a; scrapy s…

【S500无人机】--地面端下载

之前国庆的时候导师批了无人机&#xff0c;我们几个也一起研究了几次&#xff0c;基本把无人机组装方面弄的差不多了&#xff0c;还差个相机搭载&#xff0c;今天我们讲无人机的调试 硬件配置如下 首先是地面端下载&#xff0c;大家可以选择下载&#xff1a; Mission Planne地…