当前位置: 首页 > news >正文

【用户登录】模块之登录认证+鉴权业务逻辑

用户登录——⭐认证功能的流程图:


⭐鉴权流程图:


用户登录功能的Java代码实现

1. 实体类-User

orm框架:JPA

@Table(name = "user_tab")
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Column(name="user_id")private Long id;@Column(name="user_name")private String username;@Column(name="user_password")private String password;@Column(name="user_phone")private String phone;@Column(name="user_nickname")private String nickname;@Column(name="user_create_by")private String createBy;@Column(name="user_create_time")private Date createTime;@Column(name="user_update_time")private Date updateTime;@Column(name="user_role_id")private Long roleId;
}

2. UserDao

@Repository
public interface UserDao extends JpaRepository<User,Long> {//根据user的username和password查询该用户User findByUsernameAndPassword(String username,String password);
}

3. UserService业务层接口

public interface UserService {//全查询List<User> findAllUsers();//1027-【从数据库读取用户名信息存入布隆过滤器中】void warnUpUsernames();//1027-【用户登录】User login(String username, String password);}

4. ⭐UserServiceImpl业务实现类

@Service
@Slf4j
public class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao;@Autowiredprivate StringRedisTemplate stringRedisTemplate;//全查询@Overridepublic List<User> findAllUsers() {return userDao.findAll();}//1027-【从数据库读取用户名信息存入布隆过滤器中】@Overridepublic void warnUpUsernames() {userDao.findAll().forEach(u -> {stringRedisTemplate.opsForValue().getOperations().execute(new DefaultRedisScript<Long>("return redis.call('bf.add',KEYS[1],ARGV[1])", Long.class),new ArrayList<String>() {{add("whiteUsernames");}}, u.getUsername());});}//1027-【用户登录】@Overridepublic User login(String username, String password) {if(!StringUtils.hasText(username)){throw new UsernameIsEmptyException("用户名为空异常");}username = username.trim();if(checkFromWhite(username)){throw new UsernameNotFoundException("用户名不存在异常");}User user = userDao.findByUsernameAndPassword(username, password);if(Objects.isNull(user)){throw  new BadCredentialsException("用户名|密码错误");}return user;}//判断用户名是否存在于布隆过滤器private boolean checkFromWhite(String username) {Long isExist = stringRedisTemplate.opsForValue().getOperations().execute(new DefaultRedisScript<Long>("return redis.call('bf.exists',KEYS[1],ARGV[1])", Long.class),new ArrayList<String>() {{add("whiteUsernames");}}, username);return isExist.intValue() == 0;}

5. ⭐UserController控制层接口

@Api(tags = "用户模块接口")
@RestController
@RequestMapping("/api/user")
@Slf4j
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate StringRedisTemplate stringRedisTemplate;//1027-【全查询】@ApiOperation(value = "findAllUsers",notes = "查询所有用户,需要当前用户登录状态")@GetMapping("/findAllUsers")@BmsRole(value="1")public HttpResp<List<User>> findAllUsers(){return HttpResp.success(userService.findAllUsers());}//1027-【用户登录】@ApiOperation(value = "login",notes = "用户登录")@GetMapping("login")public HttpResp login(HttpServletResponse response, String username, String password){//首先调用AuthorityService的login方法进行用户登录验证,返回一个User对象。User user = userService.login(username,password);//然后生成一个JWT作为用户的身份认证凭证,其中包含了用户名和过期时间等信息。//使用JWT.create()创建JWT对象,并使用withClaim()方法设置用户名,withExpiresAt()方法设置过期时间。String salt = Base64.getEncoder().encodeToString((username+":"+password).getBytes(StandardCharsets.UTF_8));log.debug("user:{}",user);String token = JWT.create().withClaim("username", username).withClaim("roleId",""+user.getRoleId()).withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 30))   //30分钟令牌过期.sign(Algorithm.HMAC256(salt)); //使用Algorithm.HMAC256(salt)指定加密算法和密钥,对JWT进行签名。log.debug("用户验证通过,生成token为:{}",token);//将生成的JWT存储到Redis缓存中,使用stringRedisTemplate.opsForValue().set()方法设置键值对,并使用stringRedisTemplate.expire()方法设置过期时间stringRedisTemplate.opsForValue().set(token,salt);stringRedisTemplate.expire(token,60, TimeUnit.MINUTES); //60分钟redis缓存token过期response.addCookie(new Cookie("token",token));  //将JWT作为Cookie添加到HTTP响应中,使用response.addCookie()方法return HttpResp.success(user);  //最后返回一个成功的响应,消息体中包含了登录成功的用户对象}}

用户认证解决方案

1. 配置部署拦截器

@Configuration
@Slf4j
public class BmsMvcConfig implements WebMvcConfigurer {@Beanpublic AuthorityInterceptor authorityInterceptor(){log.debug("BmsMvc拦截器启动成功:{}..........",new Date());return new AuthorityInterceptor();}@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(authorityInterceptor()).addPathPatterns("/api/**").excludePathPatterns("/api/user/login");}
}

2. ⭐自定义拦截器

@Slf4j
public class AuthorityInterceptor implements HandlerInterceptor {@Autowiredprivate StringRedisTemplate stringRedisTemplate;/**** @param request* @param response* @param handler   当前拦截器拦截的方法* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.debug("已进入拦截器:{}",new Date());String token = request.getHeader("token");//1.从redis中读取token,如果不存在,则用户是非法用户,抛出自定义异常类InvalidTokenExceptionBoolean isRedis = stringRedisTemplate.hasKey(token);if(!isRedis) throw new InvalidTokenException("无效的token");String salt = stringRedisTemplate.opsForValue().get(token);log.debug("salt:{}",salt);DecodedJWT decodedJWT = JWT.require(Algorithm.HMAC256(salt)).build().verify(token);//2.token验证完成正确String roleId = decodedJWT.getClaim("roleId").asString();log.debug("------->roleId:{}",roleId);HandlerMethod method = (HandlerMethod) handler;//System.out.println("----->"+method.getMethod().getDeclaredAnnotation(GetMapping.class));BmsRole bmsRole= method.getMethod().getDeclaredAnnotation(BmsRole.class);String requiredRolId = bmsRole.value();if(!roleId.equals(requiredRolId)){throw new PermissionDeniedException("您没有足够的权限");}//获取请求对象的角色名称//获取请求的地址(uri)
//        String requestURI = request.getRequestURI();
//        requestURI = requestURI.substring(requestURI.lastIndexOf("/") + 1);
//        log.debug("请求路径uri:{}",requestURI);//URL/URI
//        System.out.println(handler.getClass());return HandlerInterceptor.super.preHandle(request, response, handler);}
}

3. 在spring.factories文件加载部署

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.****.bms.authority.config.BmsMvcConfig,com.****.bms.authority.handler.UserExceptionHandler

未完待续......

相关文章:

【用户登录】模块之登录认证+鉴权业务逻辑

用户登录——⭐认证功能的流程图&#xff1a; ⭐鉴权流程图&#xff1a; 用户登录功能的Java代码实现 1. 实体类-User orm框架&#xff1a;JPA Table(name "user_tab") Entity Data NoArgsConstructor AllArgsConstructor public class User implements Serializ…...

开启CETOS 裸奔了一年的服务器开启firewall防火墙

记录一下关于firewall&#xff0c;博主非运维专家或服务器专家。 背景 客户有一台裸奔运行了一年多的系统有公网但发现没有开防火墙&#xff0c;iptables和firewall均是关闭状态&#xff0c;通过扫描发现很多漏洞。根据客户要求对端口进行重新梳理且关闭不必要或有潜在风险的…...

eslint识别不了别名解决方法

第一步 npm i eslint-import-resolver-alias -D第二步&#xff1a;在 eslintrc.js 配置 module.exports {settings: {import/resolver: {alias: {map: [// 这里参照webpack的别名配置映射[, ./src]],// 引用的时候可以忽略后缀extensions: [.vue, .js, .ts, .tsx, .jsx, .json…...

【windows 脚本】netsh命令

netsh 是 Windows 操作系统中的一个命令行工具&#xff0c;用于配置和管理网络设置。它提供了一系列的命令和参数&#xff0c;可以用于配置网络接口、防火墙、路由表等网络相关的设置。以下是一些常用的 netsh 命令和用法&#xff1a; 配置静态IP&#xff0c;IP地址、子网掩码和…...

二叉树三种遍历的递归与非递归写法

目录 ​编辑 一&#xff0c;前序遍历 题目接口&#xff1a; 递归解法&#xff1a; 非递归解法&#xff1a; 二&#xff0c;中序遍历 题目接口&#xff1a; 递归解法&#xff1a; 非递归写法&#xff1a; 三&#xff0c;后序遍历 题目接口&#xff1a; 递归解法&…...

虹科 | 解决方案 | 汽车示波器 远程诊断方案

车厂总部专家实时指导你修车 当一线汽修技师遇到疑难问题无从下手时&#xff0c;可以准备好pico汽车示波器套装&#xff0c;并戴上我们的M400智能AR眼镜&#xff0c;通过语音操作&#xff0c;呼叫主机厂的技术支持老师&#xff1b;老师通过AR眼镜上的摄像头老师可以实时看到现…...

Unity ScrollView最底展示

Unity ScrollView最底展示 问题方案逻辑 问题 比如在做聊天界面的时候我们肯定会使用到ScrollView来进行展示我们的聊天内容&#xff0c;那么这个时候来新消息的时候就需要最底展示&#xff0c;我认为这里有两种方案&#xff1b; 一种是通过算法每一条预制体的高度*一共多少…...

linux常用基本命令大全的使用(三)

&#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页石马农青衿 &#x1f304;每日一句&#xff1a;努力一点&#xff0c;优秀一点 &#x1f4d1;前言 本文主要是linux常用基本命令面试篇文章&#xff0c;如果有什么…...

Qt 实现软件启动界面动画

实现软件启动界面&#xff0c;用到QSplashScreen类。 效果 启动界面 描述 QSplashScreen小部件提供了一个可以在应用程序启动期间显示的启动画面。 启动画面通常是在应用程序启动时显示的小部件。启动画面通常用于启动时间较长的应用程序&#xff08;例如需要花费一些时间来建…...

2000-2021年三批“智慧城市”试点名单匹配数据

2000-2021年三批“智慧城市”试点名单匹配数据 1、时间&#xff1a;2000-2021年 2、指标&#xff1a;行政区划代码、地区、所属省份、年份、智慧城市试点、最早试点年份 3、来源&#xff1a;住建部公布的三批“国家智慧城市名单” 4、说明&#xff1a;内含原始文件和匹配结…...

H5游戏分享-烟花效果

<!DOCTYPE html> <html dir"ltr" lang"zh-CN"> <head> <meta charset"UTF-8" /> <meta name"viewport" content"widthdevice-width" /> <title>点击夜空欣赏烟花</title> <sc…...

底层驱动day8作业

代码&#xff1a; //驱动程序 #include<linux/init.h> #include<linux/module.h> #include<linux/of.h> #include<linux/of_gpio.h> #include<linux/gpio.h> #include<linux/timer.h>struct device_node *dnode; //unsigned int gpiono; …...

openWRT SFTP 实现远程文件安全传输

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f516;系列专栏&#xff1a; C语言、Linux、 Cpolar ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 文章目录 前言 1. openssh-sftp-server 安装2. 安装cpolar工具3.配置SFTP远程访问4.固定远程连接地址 前言 本次教程我…...

麒麟KYLINOS2303版本上使用KDE桌面共享软件

原文链接&#xff1a;麒麟KYLINOS2303版本上使用KDE桌面共享软件 hello&#xff0c;大家好啊&#xff0c;今天给大家推荐一个在麒麟KYLINOS桌面操作系统2303版本上使用KDE桌面共享软件的文章&#xff0c;通过安装KDE桌面共享软件&#xff0c;可以让远程vnc客户端连接访问本机桌…...

H5游戏源码分享-手机捉鬼游戏

H5游戏源码分享-手机捉鬼游戏 一款考验手速的游戏 <!DOCTYPE html> <html><head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8"><title>手机捉鬼 微信HTML5在线朋友圈游戏</title><meta name&…...

vite中将css,js文件归类至文件夹

build: {chunkSizeWarningLimit: 1500,rollupOptions: {output: {// 最小化拆分包manualChunks(id) {if (id.includes(node_modules)) {return id.toString().split(node_modules/)[1].split(/)[0].toString()}},// 用于从入口点创建的块的打包输出格式[name]表示文件名,[hash]…...

【通信原理】第一章|绪论|信息度量和通信系统的性能指标

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量博客汇总 绪论 1. 信息和信息的度量 定义信息…...

基于STM32+OneNet设计的物联网智能鱼缸(2023升级版)

基于STM32+OneNet设计的智能鱼缸(升级版) 一、前言 随着物联网技术的快速发展,智能家居和智能养殖领域的应用越来越广泛。智能鱼缸作为智能家居和智能养殖的结合体,受到了越来越多消费者的关注。本项目设计一款基于STM32的物联网智能鱼缸,通过集成多种传感器和智能化控制模…...

NET-MongoDB的安装使用

一&#xff0e;下载 MongoDB 点击 Select package 选择自己所需版本后点击下载&#xff0c;本文选用Windows 6.0版本以上 二、配置MongoDB 在 Windows 上&#xff0c;MongoDB 将默认安装在 C:\Program Files\MongoDB 中。 将 C:\Program Files\MongoDB\Server\version_numbe…...

简化geojson策略

1、删除无用的属性&#xff0c;也就是字段&#xff0c;在shp的时候就给删了 用arcgis等等软件都可以做到 2、简化坐标的小数位数 &#xff08;1&#xff09;网上推荐的办法&#xff0c;俺不会Python… github.com/perrygeo/geojson-precision &#xff08;2&#xff09;曲线…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库&#xff08;uthash库&#xff09;提供对哈希表的操作&#xff0c;文章如下&#xff1a; C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...

【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道

文/法律实务观察组 在债务重组领域&#xff0c;专业机构的核心价值不仅在于减轻债务数字&#xff0c;更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明&#xff0c;合法债务优化需同步实现三重平衡&#xff1a; 法律刚性&#xff08;债…...

使用ch340继电器完成随机断电测试

前言 如图所示是市面上常见的OTA压测继电器&#xff0c;通过ch340串口模块完成对继电器的分路控制&#xff0c;这里我编写了一个脚本方便对4路继电器的控制&#xff0c;可以设置开启时间&#xff0c;关闭时间&#xff0c;复位等功能 软件界面 在设备管理器查看串口号后&…...

VSCode 没有添加Windows右键菜单

关键字&#xff1a;VSCode&#xff1b;Windows右键菜单&#xff1b;注册表。 文章目录 前言一、工程环境二、配置流程1.右键文件打开2.右键文件夹打开3.右键空白处打开文件夹 三、测试总结 前言 安装 VSCode 时没有注意&#xff0c;实际使用的时候发现 VSCode 在 Windows 菜单栏…...