项目练习:SpringBoot整合SpringSecurity

一、理论知识铺垫

1、一般性的登陆鉴权的流程

在这里插入图片描述

2、SpringSecurity的本质

过滤链
在这里插入图片描述

3、SpringSecurity的基本登陆流程原理

在这里插入图片描述

二、个性化SpringSecurity功能开发

1、自定义Security认证功能

自定义UserDetailsService,实现Security连接数据库,进行身份认证

  • 创建user表
  • 集成mybatis,实现数据库查询功能
  • 创建LoginUser(它是UserDetails的实现类)
  • 在UserDetailsService实现类中去查询数据库,替换默认的InMemoryUserDetailsManager
  • 向SpringBoot容器中注入BCryptPasswordEncoder类
    这个类的作用,不仅是认证的时候matches密码,在注册账号的时候,也要encode密码,存入数据库

2、开发登陆接口

自定义登录接口,替换默认登录页

  • 创建controller接口,创建service层,在service层中调用authenticationManager.authenticate,触发UserDetailsService的查询数据库认证逻辑。
  • 在SecurityConfig中,新增配置,注入AuthenticationManager,配置filterChain,放行login请求
  • controller中调用service
  • 生成一个随机的uuid,拼接固定的前缀,用于生成jwt和redis中的key
  • 把用户信息存入redis中
  • 创建jwt返回给前端
  • 可以发现,用户信息没有放入token发给前端,更加安全。

3、其它接口校验

这一块,是用于用户登陆后,访问其它需要认证的接口时,携带token参数,通过token来认证用户信息的步骤。
所以,这种校验是在每个接口前就要进行的,这种时候,我们应该要想到拦截器和过滤器来实现这个功能。
security本质是一连串的过滤器组成的过滤器链,所以,这个功能放在过滤器中实现。

定义Jwt认证过滤器

  • 创建过滤器JwtAuthenticationTokenFilter,继承OncePerRequestFilter
  • 从request的header中获取token
  • 解析token获取其中userKey
  • 通过userKey,从Redis中获取用户信息
  • 验证登陆的loginUser是否超时,并刷新Redis数据
  • 创建authenticationToken,存入SecurityContextHolder中

4、退出登陆

清除Redis中的token,清除SecurityContextHolder中的用户认证信息
注意,这块无需开发controller接口,直接在SecurityConfig增加一个退出的请求地址即可。

  • 修改SecurityConfig配置,指定logout请求地址以及LogoutSuccessHandler,负责退出具体操作。
    handler的方式,就要额外处理一下给浏览器的数据写回
    相对来讲,写controller接口,貌似方便一些。

5、认证功能相关表

1~4步骤的开发都是关于security的认证功能,涉及到的表就一个sys_user表即可。

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
  `user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `dept_id` bigint(20) DEFAULT NULL COMMENT '部门ID',
  `user_name` varchar(30) NOT NULL COMMENT '用户账号',
  `nick_name` varchar(30) NOT NULL COMMENT '用户昵称',
  `user_type` varchar(2) DEFAULT '00' COMMENT '用户类型(00系统用户)',
  `email` varchar(50) DEFAULT '' COMMENT '用户邮箱',
  `phonenumber` varchar(11) DEFAULT '' COMMENT '手机号码',
  `sex` char(1) DEFAULT '0' COMMENT '用户性别(0男 1女 2未知)',
  `avatar` varchar(100) DEFAULT '' COMMENT '头像地址',
  `password` varchar(100) DEFAULT '' COMMENT '密码',
  `status` char(1) DEFAULT '0' COMMENT '帐号状态(0正常 1停用)',
  `del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
  `login_ip` varchar(128) DEFAULT '' COMMENT '最后登录IP',
  `login_date` datetime DEFAULT NULL COMMENT '最后登录时间',
  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='用户信息表';

-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES ('1', '103', 'admin', '若依', '00', 'ry@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2025-01-20 15:57:58', 'admin', '2024-12-16 10:35:31', '', '2025-01-20 15:57:58', '管理员');
INSERT INTO `sys_user` VALUES ('2', '105', 'ry', '若依', '00', 'ry@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2025-01-11 09:46:43', 'admin', '2024-12-16 10:35:31', '', '2025-01-11 09:46:43', '测试员');
INSERT INTO `sys_user` VALUES ('5', '105', 'test', '测试', '00', '', '', '0', '', '$2a$10$B6aytqjmXyw10PEDdwTjC.S0UT/dGjdMIsKqiVzMJ.ktP.iMgMQ5G', '0', '0', '', null, 'ry', '2024-12-20 19:29:40', '', null, null);

6、鉴权功能

定义:不同的用户,使用的功能不同,对数据的操作权限不同。

一般有两部分
1、前端根据用户权限,隐藏菜单或按钮。
2、后端的接口权限控制,数据权限控制。

1、功能设计

一般的后台管理系统,都分为这几个部分:目录、菜单、按钮
目录:就是指包含自菜单的菜单,可以展开的菜单,点击菜单,主页面不会切换。
菜单:菜单就是没有子菜单的菜单,点击菜单,主页面会切换。
按钮:页面上的增删改查、导出、上传等按钮
可以根据自己业务的需求,进行适当的扩展。

2、表设计

用户表:sys_user
部门表:sys_dept
角色表:sys_role
用户角色表:sys_user_role
角色权限表:sys_role_menu
权限表:sys_menu,权限表相对来讲设计最复杂。
因为,菜单之间存在父子关系,所以,要设计parent_id,保存每条数据的关联关系。
然后,菜单权限,我这里是设计成3层,目录,菜单,按钮
在这里插入图片描述在这里插入图片描述

RBAC:是基于角色的权限设计模型
所以,我们可以用用户直接关联角色,也可以用部门关联角色
根据自己的需要,进行相关设计。

这块的查询逻辑要分三块:
1、admin角色,直接返回所有权限,不用查询数据库。
2、没有绑定角色的user,直接根据userId查权限。
3、绑定多个roleId的user,根据roleIds,循环遍历查询权限。
mybatis实现表与表之间一对一和一对多的关系,用association和collection实现。
如下:
SysUser和SysDept是一对一
SysUser和roles是一对多

    <resultMap type="SysUser" id="SysUserResult">
        <id     property="userId"       column="user_id"      />
        <association property="dept"    javaType="SysDept"         resultMap="deptResult" />
        <collection  property="roles"   javaType="java.util.List"  resultMap="RoleResult" />
    </resultMap>

在这里插入图片描述

3、Security实现

1、从数据库查询出菜单权限数据,存入用户信息中。
2、通过@EnableMethodSecurity+@PreAuthorize注解给接口标识所需权限,在用户请求接口时,比对权限。

spring-security-config.jar
5.5.x用:@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
5.7.x用:@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true)

7、自定义失败处理

主要包括两部分:认证失败处理,授权失败处理

在SpringSecurity中,如果我们在认证或者授权的过程中出现了异常会被ExceptionTranslationfilter捕获到。在ExceptionTranslationFilter中会去判断是认证失败还是授权失败出现的异常。

如果是认证过程中出现的异常会被封装成AuthenticationException然后调用AuthenticationEntryPoint对象的方法去进行异常处理。
如果是授权过程中出现的异常会被封装成AccessDeniedException然后调用AccessDeniedHandler对象的方法去进行异常处理。

所以如果我们需要自定义异常处理,我们只需要自定义AuthenticationEntryPoint和AccessDeniedHandler然后配置给SpringSecurity即可。

8、跨域配置

实现WebMvcConfigurer接口,并注入一个CorsFilter即可。

参考:SpringSecurity(前后端分离)(三更)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值