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

SpringSecurity+jwt+captcha登录认证授权总结

SpringSecurity+jwt+captcha登录认证授权总结

版本信息:

springboot 3.2.0、springSecurity 6.2.0、mybatis-plus 3.5.5

认证授权思路和流程:
未携带token,访问登录接口:

1、用户登录携带账号密码

2、请求到达自定义Filter,自定义Filter(如JwtAuthenticationTokenFilter)继承OncePerRequestFilter(此Filter只会进行一次过滤,在请求返回时,不会再进行调用),在SecurityConfig中配置,将自定义Filter添加到过滤器链中并加在UsernamePasswordAuthenticationFilter过滤器之前

3、自定义Filter逻辑

3.1、查询到用户未携带token,直接放行,进入到后面认证流程

3.2、将用户信息封装成Authentication对象,调用authticate()方法进行验证,一直到DaoAuthenticationProvider中,会调用UserDetailService的loadUserByUserName()方法;自定义UserDetailServiceImpl继承UserDetailService接口;重写其loadUserByUserName()方法;查到用户后,封装成UserDetail对象返回

4、调用passwordEncoder的验证方法进行用户信息的认证(一般使用BCryptPasswordEncoder,创建此Bean并放入容器中)

5、认证通过后,使用JWT创建token并放到redis中;返回token到前端

携带token访问:

1、请求到达自定义Filter中,获取token,先验证token的正确性,从token中获取到userId,根据userId从redis中获取用户信息,将用户信息封装成Authentication对象,放进SecurityContextHolder中,后面的过滤器会在SecurityContextHolder中获取用户的信息

2、请求到达FilterSecurityInterceptor,在springSecurity中默认使用FilterSecurityInterceptor来进行权限校验;FilterSecurityInterceptor会从SecurityContextHolder中获取Authentication,然后获取其中的权限信息,判断当前用户是否拥有当前资源的访问权限;

3、通过权限判断,获取资源返回给前端;

登录认证流程图:

在这里插入图片描述

基于RBAC的授权控制:
RBAC概念:

Role-Based Access Control,中文意思是:基于角色(Role)的访问控制。这是一种广泛应用于计算机系统和网络安全领域的访问控制模型。

简单来说,就是通过将权限分配给角色,再将角色分配给用户,来实现对系统资源的访问控制。一个用户拥有若干角色,每一个角色拥有若干权限。这样,就构造成“用户-角色-权限”的授权模型。在这种模型中,用户与角色之间,角色与权限之间,一般是多对多的关系

模型:

在这里插入图片描述

在数据库中主要体现用户表角色表菜单表用户角色关联表角色菜单关联表五个模型:

CREATE TABLE "mySchema"."t_user"
(
"id" INT IDENTITY(1, 1) NOT NULL,
"username" VARCHAR(100) NOT NULL,
"password" VARCHAR(100) NOT NULL,
"email" VARCHAR(100) NOT NULL,
"phone" VARCHAR(100),
UNIQUE("id"),
UNIQUE("username"),
UNIQUE("email"),
UNIQUE("phone"),
NOT CLUSTER PRIMARY KEY("id")) STORAGE(ON "MAIN", CLUSTERBTR) ;COMMENT ON TABLE "mySchema"."t_user" IS '用户表';
COMMENT ON COLUMN "mySchema"."t_user"."id" IS '用户id';
COMMENT ON COLUMN "mySchema"."t_user"."username" IS '用户名';
COMMENT ON COLUMN "mySchema"."t_user"."password" IS '密码';
COMMENT ON COLUMN "mySchema"."t_user"."email" IS '用户邮箱';
COMMENT ON COLUMN "mySchema"."t_user"."phone" IS '电话';CREATE TABLE "mySchema"."sys_role"
(
"id" BIGINT IDENTITY(1, 1) NOT NULL,
"name" VARCHAR(128) DEFAULT NULL,
"role_key" VARCHAR(100) DEFAULT NULL,
"status" CHAR(1) DEFAULT '0',
"del_flag" INT DEFAULT 0,
"create_by" BIGINT DEFAULT NULL,
"create_time" DATETIME(6) DEFAULT NULL,
"update_by" BIGINT DEFAULT NULL,
"update_time" DATETIME(6) DEFAULT NULL,
"remark" VARCHAR(500) DEFAULT NULL,
NOT CLUSTER PRIMARY KEY("id")) STORAGE(ON "MAIN", CLUSTERBTR) ;COMMENT ON TABLE "mySchema"."sys_role" IS '角色表';
COMMENT ON COLUMN "mySchema"."sys_role"."id" IS '角色id';
COMMENT ON COLUMN "mySchema"."sys_role"."name" IS '角色名称';
COMMENT ON COLUMN "mySchema"."sys_role"."role_key" IS '角色权限字符串';
COMMENT ON COLUMN "mySchema"."sys_role"."status" IS '角色状态(0正常, 1停用)';
COMMENT ON COLUMN "mySchema"."sys_role"."del_flag" IS '删除标志(0未删除,1已删除)';
COMMENT ON COLUMN "mySchema"."sys_role"."remark" IS '备注';CREATE TABLE "mySchema"."sys_menu"
(
"id" BIGINT IDENTITY(2, 1) NOT NULL,
"menu_name" VARCHAR(64) DEFAULT 'NULL' NOT NULL,
"path" VARCHAR(200) DEFAULT NULL,
"component" VARCHAR(50) DEFAULT NULL,
"visible" CHAR(1) DEFAULT '0',
"status" CHAR(1) DEFAULT '0',
"perms" VARCHAR(100) DEFAULT NULL,
"icon" VARCHAR(100) DEFAULT '#',
"create_by" BIGINT DEFAULT NULL,
"create_time" DATETIME(6) DEFAULT CURRENT_TIMESTAMP,
"update_by" BIGINT DEFAULT NULL,
"update_time" DATETIME(6) DEFAULT CURRENT_TIMESTAMP,
"delete_f1ag" INT DEFAULT 0,
"remark" VARCHAR(500) DEFAULT NULL,
UNIQUE("id"),
NOT CLUSTER PRIMARY KEY("id")) STORAGE(ON "MAIN", CLUSTERBTR) ;COMMENT ON TABLE "mySchema"."sys_menu" IS '菜单表';
COMMENT ON COLUMN "mySchema"."sys_menu"."menu_name" IS '菜单名';
COMMENT ON COLUMN "mySchema"."sys_menu"."path" IS '路由地址';
COMMENT ON COLUMN "mySchema"."sys_menu"."component" IS '组件路径';
COMMENT ON COLUMN "mySchema"."sys_menu"."visible" IS '菜单状态(0显示1隐藏)';
COMMENT ON COLUMN "mySchema"."sys_menu"."status" IS '菜单状态(0正常1停用)';
COMMENT ON COLUMN "mySchema"."sys_menu"."perms" IS '权限标识';
COMMENT ON COLUMN "mySchema"."sys_menu"."icon" IS '菜单图标';
COMMENT ON COLUMN "mySchema"."sys_menu"."delete_f1ag" IS '是否删除(0未删除1已删除)';
COMMENT ON COLUMN "mySchema"."sys_menu"."remark" IS '备注';CREATE TABLE "mySchema"."sys_user_role"
(
"user_id" BIGINT DEFAULT 0 NOT NULL,
"role_id" BIGINT DEFAULT 0 NOT NULL,
NOT CLUSTER PRIMARY KEY("user_id", "role_id")) STORAGE(ON "MAIN", CLUSTERBTR) ;COMMENT ON TABLE "mySchema"."sys_user_role" IS '用户角色表';
COMMENT ON COLUMN "mySchema"."sys_user_role"."user_id" IS '用户id';
COMMENT ON COLUMN "mySchema"."sys_user_role"."role_id" IS '角色id';CREATE TABLE "mySchema"."sys_role_menu"
(
"role_id" BIGINT DEFAULT 0 NOT NULL,
"menu_id" BIGINT DEFAULT 0 NOT NULL,
NOT CLUSTER PRIMARY KEY("role_id", "menu_id")) STORAGE(ON "MAIN", CLUSTERBTR) ;COMMENT ON TABLE "mySchema"."sys_role_menu" IS '角色菜单关联表';
COMMENT ON COLUMN "mySchema"."sys_role_menu"."role_id" IS '角色id';
COMMENT ON COLUMN "mySchema"."sys_role_menu"."menu_id" IS '菜单id';

权限流程:

用户表、角色表、菜单表、部门表、用户角色关联表、角色菜单关联表;数据权限分为5种:个人、全部、本部门、指定部门、本部门及以下
链路:

1、用户注册,指定部门;创建角色,给角色赋菜单权限、数据权限;给用户赋予角色;
2、用户登录,通过用户的所有角色,获取所有的菜单权限和最大数据权限;菜单数据直接展示在页面;所有数据都有创建人,则数据的部门id是创建人的部门id;
3、在访问数据接口时,通过mybatis的拦截器对用户的数据进行过滤(拼接sql),返回给前端;

captcha图片验证码:

实现思路:

1、图片验证码获取,并将验证码验证码存放起来(单机应用可放在session中,分布式应用放在redis中)

2、当用户登录时,携带验证码以及验证码的key,进入到后端从redis中获取值进行验证

<!-- 谷歌kaptcha验证码依赖 -->
<dependency><groupId>com.github.penggle</groupId><artifactId>kaptcha</artifactId><version>2.3.2</version>
</dependency>

代码思路:

1、生成验证码

public Result<CaptchaVO> getCaptcha() throws IOException {// 生成文字验证码String content = defaultKaptcha.createText();// 生成图片验证码ByteArrayOutputStream outputStream = null;BufferedImage image = defaultKaptcha.createImage(content);outputStream = new ByteArrayOutputStream();ImageIO.write(image, "jpg", outputStream);// 对字节数组Base64编码String str = "data:image/jpeg;base64,";String base64Img = str + Base64.getEncoder().encodeToString(outputStream.toByteArray()).replace("\n", "").replace("\r", "");CaptchaVO captchaVO = captchaService.cacheCaptcha(content);captchaVO.setBase64Img(base64Img);return Result.success(captchaVO);
}

2、存储验证码

@Service
public class CaptchaService {private Long timeout = 300L;@Autowiredprivate RedisUtils redisUtils;private final String CAPTCHA_KEY_PREFIX = "captcha:verification:";public CaptchaVO cacheCaptcha(String captcha){//生成一个随机标识符String randomStr = UUID.randomUUID().toString();//缓存验证码并设置过期时间String captchaKey = CAPTCHA_KEY_PREFIX.concat(randomStr);redisUtils.set(captchaKey, captcha, timeout, TimeUnit.SECONDS);CaptchaVO captchaVO = new CaptchaVO();captchaVO.setCaptchaKey(captchaKey);captchaVO.setExpire(timeout);captchaVO.setCaptcha(captcha);return captchaVO;}
}

3、校验验证码

Object captcha = redisUtils.get(reqVO.getCaptchaKey());
if (Objects.isNull(captcha)) {return "验证码已过期";
}
if (!captcha.equals(reqVO.getCaptcha())) {return "验证码错误";
}

http://www.mrgr.cn/news/75132.html

相关文章:

  • 开源 2 + 1 链动模式、AI 智能名片、S2B2C 商城小程序在用户留存与品牌发展中的应用研究
  • 微信小程序——实现二维码扫描功能(含代码)
  • AGI自学分享,简单有用的理论与实践
  • 世界坐标系、相机坐标系、图像物理坐标系、像素平面坐标系
  • 机器学习 - 为 Jupyter Notebook 安装新的 Kernel
  • 小面馆叫号取餐流程 佳易王面馆米线店点餐叫号管理系统操作教程
  • 程序员的数学之进制与零
  • Flink1.19编译并Standalone模式本地运行
  • 保姆级教程,免费短链平台
  • cache缺失和关联度
  • sqlmap使用教程
  • Python 异常处理试卷
  • 【HarmonyOS】鸿蒙系统在租房项目中的项目实战(一)
  • 大语言模型LLM综述
  • GRU(门控循环单元)详解
  • Siggraph Asia 2024 | Adobe发布MagicClay:可通过文字引导去对3D模型中的特定部分进行雕刻
  • 【今天的乐子】你真懂代码吗?挑战这10个笑话,程序员专属梗了解一下
  • C++《继承》
  • 企业运营的智能化升级:AI助理与SOP的融合之道
  • java八股-jvm入门-程序计数器,堆,元空间,虚拟机栈,本地方法栈,类加载器,双亲委派,类加载执行过程
  • 线程的状态有哪些?它是如何工作的?
  • SMA-BP基于黏菌算法优化BP神经网络时间序列预测
  • 解析安卓镜像包和提取DTB文件的操作日志
  • 探索AutoDL与CodeWithGPU:深度学习之旅的新起点
  • 时序论文20|ICLR20 可解释时间序列预测N-BEATS
  • 【算法一周目】双指针(2)