登录相关

  • 权限管理模块(基础版)
    • 模块设计与实现
    • 优化点:
  • 前后端用户验证
    • 实现方式
  • 常见的攻击手段及防御手段

权限管理模块(基础版)

RBAC(Role-Base Access Control,基于角色的访问控制):是权限管理的常用方案。
核心:通过用户 - 角色 - 权限的三层关联,灵活分配和管理权限。并不将用户和全新啊直接绑定。适合多用户多权限场景。

模块设计与实现

以Java + Spring Boot + Spring Security为例

1、实体设计(库表设计)
需要具备3个实体(用户、角色、权限),以及2个关系表(用户-角色、角色-权限)。

// 用户实体
@Data
public class User {private Long id;private String username;private String password; // 加密存储(如BCrypt)private Integer status; // 1-启用,0-禁用// 关联角色(一对多,通过user_role表)private List<Role> roles;
}// 角色实体
@Data
public class Role {private Long id;private String name; // 角色名称(如“系统管理员”)private String code; // 角色标识(如“ROLE_ADMIN”,用于Spring Security)// 关联权限(一对多,通过role_permission表)private List<Permission> permissions;
}// 权限实体
@Data
public class Permission {private Long id;private String name; // 权限名称(如“删除用户”)private String code; // 权限标识(如“user:delete”,用于权限校验)private Integer type; // 1-菜单,2-按钮(接口)private String url; // 接口URL(如“/api/user/delete”)private Long parentId; // 父权限ID(用于菜单层级)
}
-- 用户-角色关联表
CREATE TABLE `user_role` (`id` bigint NOT NULL AUTO_INCREMENT,`user_id` bigint NOT NULL,`role_id` bigint NOT NULL,PRIMARY KEY (`id`),KEY `idx_user` (`user_id`),KEY `idx_role` (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;-- 角色-权限关联表
CREATE TABLE `role_permission` (`id` bigint NOT NULL AUTO_INCREMENT,`role_id` bigint NOT NULL,`perm_id` bigint NOT NULL,PRIMARY KEY (`id`),KEY `idx_role` (`role_id`),KEY `idx_perm` (`perm_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2、Mapper层设计,提供数据库基本操作。

public interface UserMapper {// 查询用户User selectByUsername(String username);// 查询用户的角色List<Role> selectRolesByUserId(Long userId);// 查询角色的权限List<Permission> selectPermissionsByRoleId(Long roleId);
}
public Interface RolePermissionMapper() {// CRUD
}

3、Service实现,提供查询用户权限,用户与角色,角色与权限的分配与修改。
用户登录时,查询权限,用于后续权限校验。

@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public List<String> login(String username,String password) {// 校验逻辑,判断用户是否存在return 用户信息(包含权限列表)}// 根据用户名查询用户及其关联的角色和权限public User getUserWithRolesAndPermissions(String username) {User user = userMapper.selectByUsername(username);if (user == null) {throw new UsernameNotFoundException("用户不存在");}// 查询用户关联的角色List<Role> roles = userMapper.selectRolesByUserId(user.getId());// 为每个角色查询关联的权限for (Role role : roles) {List<Permission> permissions = userMapper.selectPermissionsByRoleId(role.getId());role.setPermissions(permissions);}user.setRoles(roles);return user;}
}
// 管理用户-角色 角色-权限
@Service
public class RolePermissionService {@Autowiredprivate RolePermissionMapper rolePermissionMapper;// 给角色分配权限(先删除旧关联,再插入新关联)@Transactionalpublic void assignPermissions(Long roleId, List<Long> permIds) {// 1. 删除该角色已有的所有权限关联rolePermissionMapper.deleteByRoleId(roleId);// 2. 插入新的权限关联if (permIds != null && !permIds.isEmpty()) {List<RolePermission> list = permIds.stream().map(permId -> {RolePermission rp = new RolePermission();rp.setRoleId(roleId);rp.setPermId(permId);return rp;}).collect(Collectors.toList());rolePermissionMapper.batchInsert(list);}}
}

3、权限校验(限制到接口层面)
结合Spring Security实现接口访问时单独权限校验。
原理:

  • 将用户权限加载到上下文中。并通过注解或配置文件进行拦截。
  • Spring Security的授权流程通过 http.authorizeRequests() 对web请求进行授权保护。授权决策由 AccessDecisionManager 进行,它会对比当前访问资源所需的权限信息和用户信息中的权限信息。

步骤:

  1. 加载用户到Spring Security:
    实现UserDetailsService,将用户信息(包含角色和权限)转换为Security可识别的userDetails。
    UserDetailsService:从数据库中取出用户的账号密码。
@Service
public class CustomUserDetailsService implements UserDetailsService {@Autowiredprivate UserService userService;// 将用户信息以及对应的角色,权限交由Security管理@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {// 查询用户及其角色、权限User user = userService.getUserWithRolesAndPermissions(username);if (user == null) {throw new UsernameNotFoundException("用户不存在");}// 提取角色(需加前缀"ROLE_",符合Security规范)List<String> roleCodes = user.getRoles().stream().map(role -> "ROLE_" + role.getCode()).collect(Collectors.toList());// 提取权限标识(如"user:delete")List<String> permCodes = user.getRoles().stream().flatMap(role -> role.getPermissions().stream()).map(Permission::getCode).collect(Collectors.toList());// 合并角色和权限(Security将其统一视为"权限")List<String> authorities = new ArrayList<>();authorities.addAll(roleCodes);authorities.addAll(permCodes);// 返回Security用户对象。提供参数由Security转换用户与权限return org.springframework.security.core.userdetails.User.withUsername(user.getUsername()).password(user.getPassword()).authorities(authorities) // 角色和权限都作为authority.accountLocked(user.getStatus() == 0) // 状态为0时锁定.build();}
}
  1. 权限校验
  • 注解方式校验:在Controller方法上使用@PerAuthorize注解,指定所需要的权限。
@RestController
@RequestMapping("/api/user")
public class UserController {// 需拥有"user:delete"权限才能访问@PreAuthorize("hasAuthority('user:delete')")@DeleteMapping("/{id}")public Result deleteUser(@PathVariable Long id) {// 业务逻辑return Result.success();}// 需拥有"ROLE_ADMIN"角色才能访问@PreAuthorize("hasRole('ADMIN')") // 自动拼接"ROLE_"前缀@GetMapping("/list")public Result getUserList() {// 业务逻辑return Result.success();}
}
  • 配置列中通过URL匹配指定权限:
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true) // 开启@PreAuthorize注解
public class SecurityConfig {@Autowiredprivate CustomUserDetailsService userDetailsService;@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests(auth -> auth// 访问"/api/admin/**"需ADMIN角色.requestMatchers("/api/admin/**").hasRole("ADMIN")// 访问"/api/user/delete"需"user:delete"权限.requestMatchers("/api/user/delete/**").hasAuthority("user:delete")// 其他接口允许认证用户访问.anyRequest().authenticated());return http.build();}
}

4、前端权限适配(动态加载)
根据用户权限展示菜单和按钮。
原理:

  • 登陆后,获取当前用户权限列表(后端返回)
  • 渲染菜单/按钮时,只显示用户权限内的菜单/按钮。
// 1. 登录后获取用户权限
async function login(username, password) {const res = await api.login({ username, password });const { permissions } = res.data; // 后端返回的权限列表(如["user:delete", "menu:user"])localStorage.setItem('permissions', JSON.stringify(permissions));
}// 2. 权限判断工具函数
function hasPermission(permission) {const permissions = JSON.parse(localStorage.getItem('permissions') || '[]');return permissions.includes(permission);
}// 3. 动态渲染按钮(使用自定义指令)
Vue.directive('perm', {inserted(el, binding) {if (!hasPermission(binding.value)) {el.remove(); // 无权限则移除按钮}}
});// 4. 在模板中使用
<template><button v-perm="'user:delete'">删除用户</button>
</template>

优化点:

  • 角色继承:支持角色间的父子关系,需要在role表中添加Parent_id字段。
  • 数据权限:在功能权限基础上,控制数据可见范围(员工只能查看本人数据)。可通过在权限表中添加data_scope字段(限制全部/本部门/个人),结合SQL拦截器实现。
  • 权限缓存:可以将用户权限缓存到Redis中(key用户名,value权限列表),减少数据库压力,提高性能。(注意每次修改权限后需要考虑缓存一致性)。

前后端用户验证

交互中保证同一用户的核心:身份标识与验证机制。通过不同技术保证每次请求来自同一个用户,防止身份假冒以及会话混乱。

实现方式

1、 Cookie + Session的传统方案(适用于Web端)
最早且最成熟的方案,依赖服务器的会话存储和客户端的Cookie传递标识。
核心流程

  • 用户登录验证:
    • 登录验证通过后,在服务器内存/数据库中创建一个session(包含用户标识登录状态等信息),生成唯一的SESSIONID。
    • 后端通过Set-Cookie响应头返回客户端,客户端自动将其保存到Cookie中(通常设置HttpOnly和Secure属性)。
  • 后续请求身份确认
    • 客户端每次请求时,浏览器自动子啊请求头中Cookie字段按中携带SessionID。
    • 后端通过SessionID查询服务器的Session数据,若存在且有效(未过期),则任务是同一用户。

相关配置:

  • HttpOnly: true:禁止 JavaScript 读取 Cookie,防止 XSS 攻击窃取SessionID;
  • Secure: true:仅在 HTTPS 协议下传输 Cookie,避免明文泄露;
  • SameSite: Strict/Lax:限制 Cookie 跨域发送,防止 CSRF 攻击;
  • 会话超时机制:如 30 分钟无操作自动失效,降低SessionID被盗用的风险。

2、基于Token的无状态方案(适用于多端应用)
Token方案不依赖服务器存储会话,而是通过加密令牌传递用户信息,更适合前后端分离,移动端、小程序等场景。
核心流程

  • 生成Token:
    • 用户登陆验证通过后,后端使用密钥生成一个加密token(常见为JWT格式),包含用户Id、过期时间、签名等信息(不包含敏感数据)。
    • 后端将Token返回给客户端,客户端存储在LocalStorage、SessionStorage或App本地存储。
  • 携带Token请求
    • 客户端每次请求时,在HTTP请求头中(如Authorization:Bearer<.token>) 中携带token。
    • 后端验证Token签名(确保未篡改)和过期时间,解析出用户Id,确认是同一用户。
      JWT(JSON Web Token)示例:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJ1c2VySWQiOjEsIm5hbWUiOiJKb2huIiwiZXhwIjoxNzIwMDAwMDAwfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
第一部分:算法声明(HS256);
第二部分:用户信息(用户 ID、过期时间);
第三部分:签名(用密钥生成,确保内容未被篡改)。

相关配置

  • 短期有效期:Token 过期时间设为 15-30 分钟,降低被盗用后的风险;
  • 刷新 Token 机制:同时返回access_token(短期)和refresh_token(长期,如 7 天),过期后用refresh_token重新获取access_token,避免频繁登录;
  • Token 黑名单:用户登出或密码修改时,将旧 Token 加入黑名单(Redis 存储),强制失效。

3、基于设备指纹与生物识别的增强方案(高安全性场景)
在金融、支付等安全性高的场景中,需要结合设备信息或生物特性辅助验证"同一用户”。

  • 设备指纹验证:
    • 后端收集客户端信息(CPU信息、操作系统等),生成唯一“设备指纹”
    • 登录时,将用户ID+设备指纹绑定,后续请求若设备指纹不符(如同一账号在新设备登录),触发二次验证(如短信验证)。
  • 生物识别辅助:
    • 移动端App可结合指纹识别,面部识别,通过后才允许携带Token请求敏感接口。
    • 即使Token泄露,没有生物特征同样无法完成操作。

4、跨域场景下身份有效。
当前后端域名不同,需要配置确保身份标识能跨域传递。

  • Cookie跨域:
    • 后端设置Access-Control-Allow-Credentials: true响应头;
    • 前端请求时携带credentials: 'include’参数(如 Axios 配置);
    • Cookie 设置domain: .parent.com(主域名一致时),允许子域名共享。
  • Token跨域
    • 无跨域限制,只在请求投中正确携带Token即可(不受Cookie同源策略影响)。

补充
Cookie同源策略:是浏览器的一种安全机制,用于防止不同源的网页之间相互访问数据,从而保护用户信息的安全。所谓“同源”,指的是两个网页的协议、域名和端口都相同。
作用:
同源策略的主要目的是防止恶意网站窃取用户数据。例如,如果用户登录了一个银行网站A,然后又访问了另一个网站B,如果没有同源策略,网站B可以读取网站A的Cookie,从而获取用户的敏感信息。

常见的攻击手段及防御手段

针对身份盗用的典型攻击(XSS、CSRF、重放攻击等),需要针对性防护。

1、防御XSS攻击(防止标识被窃取)
XSS攻击通过注入恶意脚本窃取前端存储的标识(如LocalStorage中的Token,document.cookie)。
预防:

  • 前端输入过滤:对用户输入内容(评论、表单)进行HTML转义(如>转义为& lt/ ); 使用框架自带的安全渲染(如React的JSX自动转义,VUE的v-text)。
  • 后端输出编码:返回给前端的数据中,对HTML/JS特殊字符编码,避免直接渲染未处理的用户输入。
  • 启用CSP(内容安全策略):

2、防御CSRF攻击(防止身份被滥用)
CSRF攻击:利用用户已登录的身份,诱导用户在第三方网站上发起恶意请求(如转账),防护措施:

  • SameSite Cookie:通过SameSite-Strict限制Cookie仅在同域请求中携带,彻底阻止跨域CSRF。
  • CSFR Token:对敏感操作(如表单操作、转账),后端生成随机CSFR Token(绑定Session),前端表单携带该Token,后端验证Token的有效性后才处理请求。
    例:前端表单隐藏字段,后端对比 Session 中的 Token。

3、防止重放攻击(防止标识被重复使用)
攻击者窃取Token后重复发送请求(如重复下单),防护措施:

  • Token短期有效+刷新时间
    • assess_token(访问令牌)有效期15~20分钟,用于日常请求;
    • refresh token(刷新令牌)有效期7天,用于过期后获取access_token,且刷新时验证设备信息(如设备信息);
    • 每次刷新后,旧access_token立即失效,refresh_token采用“一次性”机制(使用后立即失效,返回新的refresh_token)。
  • 请求时间戳+nonce
    前端请求时携带timestamp(当前时间戳)和nonce(随机字符串,仅用一次)后端验证:
    • 时间戳与服务器时间 不差5分钟(防止过期请求)。
    • nonce在Redis记录,已使用过的nonce直接拒绝(防止重复请求)。

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

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

相关文章

征服与守护:从拉里·埃里森看八号人格的职场王者之道

真正的强者&#xff0c;从不遵守别人的规则2010年&#xff0c;加利福尼亚州的圣何塞机场迎来了一架不速之客——一架意大利产的马基战斗机以一种极其霸道的姿态降落在跑道上。舱盖打开&#xff0c;走下来的不是空军飞行员&#xff0c;而是一位身穿飞行员服、戴着墨镜的企业家&a…

【Linux系统】命名管道与共享内存

前言&#xff1a; 上文我们讲到了匿名管道【Linux系统】匿名管道以及进程池的简单实现-CSDN博客 本文我们来讲一讲命名管道与共享内存 命名管道 上面我们讲到&#xff0c;匿名管道只能用于有血缘关系&#xff08;尤其父子&#xff09;的进程进行通信&#xff01;但如果…

搜索体验优化:ABP vNext 的查询改写(Query Rewrite)与同义词治理

&#x1f50e; 搜索体验优化&#xff1a;ABP vNext 的查询改写&#xff08;Query Rewrite&#xff09;与同义词治理 &#x1f4da; 目录&#x1f50e; 搜索体验优化&#xff1a;ABP vNext 的查询改写&#xff08;Query Rewrite&#xff09;与同义词治理1. 背景与问题界定 &…

Text2API与Text2SQL深度对比:自然语言驱动的数据交互革命

在数字化浪潮中&#xff0c;如何让人机交互更加自然流畅&#xff1f;Text2API与Text2SQL技术应运而生&#xff0c;它们如同魔法般将自然语言转化为机器可执行的指令&#xff0c;让数据交互不再高不可攀。本文将深入剖析这两项技术的原理、优劣势及应用场景&#xff0c;带您领略…

数据可视化与分析平台设计与实现案例

数据可视化与分析平台设计与实现案例(python) 下面分享一个完整的 Flask 数据可视化与分析平台代码,包含所有必要的组件和功能。这个平台允许用户上传数据文件、进行基本的数据清洗、生成各种可视化图表以及查看基础统计分析结果。 产品设计 核心功能 数据上传与管理(支…

Kotlin-基础语法练习二

接上一篇博客 每个 Kotlin 程序都是由两种部分组成的&#xff1a; 1、表达式&#xff08;Expressions&#xff09;&#xff1a;用于计算值的部分&#xff0c;比如 2 3、函数调用、变量赋值等&#xff0c;它们通常会返回一个结果。2、语句&#xff08;Statements&#xff09;…

与Deepseek对话了解单片机基础知识

keil5里的c语言编程的程序烧录到单片机里具体过程是啥&#xff1f;如何能把机器语言转换为电路控制&#xff1f; 步骤 所在位置 核心工具 输入->输出 比喻 1. 编译 Keil5 (PC) 编译…

利用背景图片定位套打档案封面

某些表单设计起来比较复杂&#xff0c;或只有表单的空白图片资料。Nhdeep档案目录套打工具&#xff08;nhdeep官网www.nhdeep.com&#xff09;支持将已有的表单图片作为模版背景图片&#xff0c;然后使用文本框进行精准的位置定位&#xff0c;再进行文本替换。 背景图片定位套…

微信HOOK 实现自动下载视频

1、前言 在收发消息的接口中&#xff0c;图片和文件这类接口是相对容易自动下载&#xff0c;但是视频的下载是需要手动点击的&#xff0c;并且只有这一种下载方式&#xff0c;实现自动化也比较困难&#xff0c;一些项目的开发中&#xff0c;需要自动下载收到的视频并保存&#…

【GPT入门】第57课 详解 LLamaFactory 与 XTuner 实现大模型多卡分布式训练的方案与实践

【GPT入门】第57课 大模型多卡计算1. 理论2.LLamaFacotory实践3. xtuner3.1 介绍3.1 安装3.2 xtuner训练3.4 训练后格式转换3.5 合并基础模型与lora模型3.6 参数说明3.7 训练过程主观检验1. 理论 deepspeed的三种训练方式 zero-1&#xff0c;优化器状态分片。的优势体现在多卡…

部队多媒体信息发布系统:赋能 IPTV 与电教化,加速军营信息化变革

在科技飞速发展的当下&#xff0c;部队的信息化建设也在不断推进。多媒体信息发布系统作为一种创新的技术手段&#xff0c;正逐步融入部队的各个领域&#xff0c;为部队的现代化建设注入强大动力。​在部队 IPTV 方面&#xff0c;多媒体信息发布系统展现出卓越的性能。它打破了…

FTP/TCP上传下载文件

封装C风格地ftplib为ftp.c和ftp.h文件&#xff1a;cftplient类&#xff08;主要成员变量&#xff1a;文件大小、文件修改时间、主要成员函数&#xff1a;get函数&#xff08;远程文件名、本地文件名、核对文件时间&#xff09;、put函数&#xff08;本地文件名、服务端文件名、…

DeepSeek V3.1深度解析:一个模型两种思维,迈向Agent时代的第一步!

名人说&#xff1a;博观而约取&#xff0c;厚积而薄发。——苏轼《稼说送张琥》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录一、什么是DeepSeek V3.1&#xff1f;为什么这么火&#x1f680;1. 发布时间线回顾2.…

VsCode 便携版(绿色版)下载及配置

下载 VsCode 便携版&#xff0c;并确保所有配置和扩展都保存在一起&#xff0c;实现真正的“绿色版”效果 核心步骤概览 核心原理是在 VSCode 的主程序目录下创建一个名为 data 的文件夹&#xff0c;VSCode 启动时如果检测到这个文件夹&#xff0c;就会自动切换到便携模式&am…

使用VLLM部署大模型embedding/chat 的API

模型下载&#xff1a;一般通过modelscope提供的方式进行下载&#xff0c;速度更快&#xff0c;huggingface下模型即便开启了魔法也还是很慢&#xff0c;对于9B以上的模型都是至少15G的。 比如需要下载qwen3-embedding-8b的模型&#xff0c;可以通过提供的一段代码自动进行下载到…

Blender模型动画导入到UE5

UE5支持直接导入FBX文件&#xff0c;但在实际应用中笔者发现&#xff1a;刚开始使用的是UE5.3&#xff0c;在UE5.3中直接将.fbx文件拖入UE中导入后是一个个的零件&#xff0c;后来使用了datasmith插件等其他办法&#xff0c;怎么都没有达到想要的效果。后面升级UE5.4以后&#…

Promise详解:Promise解决ajax回调嵌套问题

目录 一、Promise是什么 二、回调地狱 三、Promise解决回调地狱的原理 四、promaise实例 一、Promise是什么 1、主要用于异步计算 2、可以将异步操作队列化&#xff0c;按照期望的顺序执行&#xff0c;返回符合预期的结果 4、可以在对象之间传递和操作promise&#xff0c…

【Kubernetes知识点】Pod调度和ConfigMaps

目录 1.如何将特定Pod调度到指定的节点&#xff1f; 2.什么是节点的亲和性&#xff1f; 3.什么是污点&#xff0c;它的主要用途是什么&#xff1f; 4.解释ConfigMap的作用。 5.Secret和ConfigMap相比较有哪些优点。 6.解释ResourceQuota的作用 1.如何将特定Pod调度到指定…

火车头使用Post方法采集Ajax页面教程

前面有写过一篇瀑布流的采集方法&#xff0c;今天在添加一个POST方法来采集Ajax刷新页面的教程。 之前的文章请看&#xff1a;火车头采集动态加载Ajax数据&#xff08;无分页瀑布流网站&#xff09; 如果遇到POST方法来架子Ajax数据&#xff0c;这和我之前写的是两个类型&…