spring security
Spring Security默认做了什么
- 保护应用程序URL,要求对应用程序的任何交互进行身份验证。
- 程序启动时生成一个默认用户“user”。
- 生成一个默认的随机密码,并将此密码记录在控制台上。
- 生成默认的登录表单和注销页面。
- 提供基于表单的登录和注销流程。
- 对于Web请求,重定向到登录页面;
- 对于服务请求,返回401未经授权。
- 处理跨站请求伪造(CSRF)攻击。
- 处理会话劫持攻击。
- 写入Strict-Transport-Security以确保HTTPS。
- 写入X-Content-Type-Options以处理嗅探攻击。
- 写入Cache Control头来保护经过身份验证的资源。
- 写入X-Frame-Options以处理点击劫持攻击。
Spring Security 的底层原理
官方文档:Spring Security的底层原理
Spring Security之所以默认帮助我们做了那么多事情,它的底层原理是传统的Servlet过滤器
Filter
下图展示了处理一个Http请求时,过滤器和Servlet的工作流程:
因此我们可以在过滤器中对请求进行修改或增强。
DelegatingFilterProxy
DelegatingFilterProxy 是 Spring Security 提供的一个 Filter 实现,可以在 Servlet 容器和 Spring 容器之间建立桥梁。通过使用 DelegatingFilterProxy,这样就可以将Servlet容器中的 Filter 实例放在 Spring 容器中管理。
FilterChainProxy
复杂的业务中不可能只有一个过滤器。因此FilterChainProxy是Spring Security提供的一个特殊的Filter,它允许通过SecurityFilterChain将过滤器的工作委托给多个Bean Filter实例。
SecurityFilterChain
SecurityFilterChain 被 FilterChainProxy 使用,负责查找当前的请求需要执行的Security Filter列表。
Multiple SecurityFilterChain
可以有多个SecurityFilterChain的配置,FilterChainProxy决定使用哪个SecurityFilterChain。如果请求的URL是/api/messages/,它首先匹配SecurityFilterChain0的模式/api/**,因此只调用SecurityFilterChain 0。假设没有其他SecurityFilterChain实例匹配,那么将调用SecurityFilterChain n。
Spring Security数据库配置
官方文档:Java自定义配置
sql
create database if not exists spring_security;
use spring_security;
drop table if exists user;
create table if not exists user
(
user_account int primary key,
user_name varchar(255),
user_password text
);
drop table if exists role;
create table if not exists role
(
role_id int primary key,
role_name varchar(255)
);
drop table if exists permission;
create table if not exists permission
(
peremission_id int primary key,
permission_name varchar(255)
);
drop table if exists user_role;
create table if not exists user_role
(
user_account int,
role_id int,
primary key (user_account, role_id),
foreign key (user_account) references user (user_account),
foreign key (role_id) references role (role_id)
);
drop table if exists role_permission;
create table if not exists role_permission
(
role_id int,
permission_id int,
primary key (role_id, permission_id),
foreign key (role_id) references role (role_id),
foreign key (permission_id) references permission (peremission_id)
);
/**
添加用户,密码123,加密方式 BCryptPasswordEncoder
*/
insert into user (user_account, user_name, user_password)
values (1, 'admin', '$2a$10$XvP0pzuaDGg2t/ZFRxsX/uAgJeKVQigngKaTc5qIP8zX7D8xNyBja'),
(2, 'user2', '$2a$10$XvP0pzuaDGg2t/ZFRxsX/uAgJeKVQigngKaTc5qIP8zX7D8xNyBja'),
(3, 'user3', '$2a$10$XvP0pzuaDGg2t/ZFRxsX/uAgJeKVQigngKaTc5qIP8zX7D8xNyBja');
insert into role (role_id, role_name)
values (1, 'root'),
(2, 'normal'),
(3, 'tourist');
insert into permission (peremission_id, permission_name)
values (1, 'r'),
(2, 'w'),
(3, 'x');
insert into user_role (user_account, role_id)
values (1, 1),
(2, 2),
(3, 3);
insert into role_permission (role_id, permission_id)
values (1, 1),
(1, 2),
(1, 3),
(2, 1),
(2, 3),
(3, 1);
-- ------------------------------------------------------------------------
select user.user_account, user_name, user_password, role_name, permission_name
from user
join user_role on user.user_account = user_role.user_account
join role on user_role.role_id = role.role_id
join role_permission on role.role_id = role_permission.role_id
join permission on role_permission.permission_id = permission.peremission_id;
drop view if exists user_role_permission;
-- 视图
/**
用户密码,角色,权限
*/
create view user_role_permission as
select user.user_account, user_name, user_password, role.role_name, permission.permission_name
from user
left join user_role on user.user_account = user_role.user_account
left join role on user_role.role_id = role.role_id
left join role_permission on role.role_id = role_permission.role_id
left join permission on role_permission.permission_id = permission.peremission_id;
-- 视图显示
select *
from user_role_permission;
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wangnan</groupId>
<artifactId>spring_security</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring_security</name>
<description>spring_security</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter-test</artifactId>
<version>3.0.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.37</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
配置
com.spring_security.config.SecurityConfig
定义密码编码器
@Bean("getpasswordEncoder")
public PasswordEncoder getpasswordEncoder() {
return new BCryptPasswordEncoder();
}
配置过滤器
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// 配置
//
http.csrf(csrf -> csrf.disable());
// 登出
http.logout(logout -> logout
.permitAll()
.logoutSuccessHandler(new LogoutSuccessMessage()));
return http.build();
}
权限控制
http.authorizeHttpRequests(
authorize -> authorize
// request 权限控制
// .requestMatchers("/perm/read").hasAuthority("r")
// .requestMatchers("/perm/write").hasAuthority("w")
// 角色控制
// .requestMatchers("/perm/write").hasRole("ROOT")
.anyRequest()
.authenticated()
);
登录认证 new的Handler是实现接口自定义的
http.formLogin(formLogin -> formLogin
.loginPage("/dologin").permitAll() //登录页面无需授权即可访问
.usernameParameter("username") //自定义表单用户名参数,默认是username
.passwordParameter("password") //自定义表单密码参数,默认是password
/* 登录失败的返回地址,使用
.successHandler(new AuthenticationSuccessfulMessage())
.failureHandler(new AuthenticationFailedMessage())
会失效
*/
// .failureUrl("/dologin?error")
.successHandler(new AuthenticationSuccessfulMessage())
.failureHandler(new AuthenticationFailedMessage())
);
认证授权异常 new的对象都是实现接口自定义的
http.exceptionHandling(
exception -> exception
// 未认证访问异常
.authenticationEntryPoint(new AuthenticationEntryPointMessage())
// 无权限异常
.accessDeniedHandler(new AccessDeniedHandlerMessage())
);
DBUserDetailsManager
package com.spring_security.config;
import com.spring_security.entity.Permission;
import com.spring_security.entity.Role;
import com.spring_security.entity.User;
import com.spring_security.mapper.UserMapper;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsPasswordService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.provisioning.UserDetailsManager;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
/*****UTF-8*****
* Description:
* Author: 王 楠
* Date: 2024/6/3 11:10
* Proverbs: 吃的苦中苦,方为人上人
*/
@Component
public class DBUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService {
private final UserMapper userMapper;
public DBUserDetailsManager(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public UserDetails updatePassword(UserDetails user, String newPassword) {
return null;
}
@Override
public void createUser(UserDetails user) {
}
@Override
public void updateUser(UserDetails user) {
}
@Override
public void deleteUser(String username) {
}
@Override
public void changePassword(String oldPassword, String newPassword) {
}
@Override
public boolean userExists(String username) {
return false;
}
/*
* 权限数组
*/
public String[] getPermissionArr(User user) {
List<Permission> permissions = user.getPermissions();
String[] permissionArr = new String[permissions.size()];
for (int i = 0; i < permissionArr.length; i++) {
permissionArr[i] = permissions.get(i).getPermissionName();
}
return permissionArr;
}
/**
角色数组
*/
public String[] getRolesArr(User user) {
List<Role> roles = user.getRoles();
String[] roleArr = new String[roles.size()];
for (int i = 0; i < roleArr.length; i++) {
roleArr[i] = roles.get(i).getRoleName();
}
return roleArr;
}
/**
* 在这个方法里标注用户的权限和角色信息,建立spring security框架里的用户对象,方法返回的就是用户画像
*
* @param username
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return null;
}
}
加载用户信息
UserDetails存放用户信息
在Spring Security中,
UserDetails
接口是一个核心接口,用于表示一个用户的基本信息,包括用户名、密码、权限等。这个接口主要由Spring Security的认证和授权机制使用,以确定用户是否有权执行特定的操作或访问特定的资源。
UserDetails
接口定义了以下方法:
String getUsername()
: 获取用户名。String getPassword()
: 获取密码。Collection<? extends GrantedAuthority> getAuthorities()
: 获取用户的权限列表。权限通常表示为GrantedAuthority
对象,其中可能包括角色(如ROLE_USER
)和其他特定的权限(如read
或write
)。boolean isAccountNonExpired()
: 指示用户的账户是否未过期。boolean isAccountNonLocked()
: 指示用户的账户是否未锁定。boolean isCredentialsNonExpired()
: 指示用户的凭证(密码)是否未过期。boolean isEnabled()
: 指示用户是否启用。
UserDetails
接口的实现类通常在应用程序中用于创建用户对象,这些对象随后由UserDetailsService
在认证过程中加载。UserDetailsService
是一个接口,用于根据用户名检索UserDetails
对象。开发者通常需要实现这个接口,以便从数据库或其他数据源加载用户信息。
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// username前端表单传来的数据
User user = userMapper.getUserByAccount(username);
if (user != null) {
// 权限数组
String[] permissionArr = getPermissionArr(user);
// 角色数组
String[] rolesArr = getRolesArr(user);
return null;
} else {
throw new UsernameNotFoundException(username);
}
}
// GrantedAuthority 权限
Collection<GrantedAuthority> authorities = new ArrayList<>();
org.springframework.security.core.userdetails.User 是UserDetails实现类
return org.springframework.security.core.userdetails.User
.withUsername(user.getUserAccount())
.password(user.getUserPassword())
/*
roles(rolesArr)
.authorities(permissionArr)
这两个不能同时用,他的源码逻辑导致的
*/
.roles(rolesArr)
.authorities(permissionArr)
.build();
登录
controller
@GetMapping("/dologin")
public String login(){
return "login";
}
html
<!--
*****UTF-8*****
* Description:
* Author: 王 楠
* Date: 2024/5/27 20:40
* Proverbs: 吃的苦中苦,方为人上人
-->
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org">
<head>
<title>登录</title>
<meta charset="UTF-8">
</head>
<body>
<h1>登录</h1>
<div th:if="${param.error}">
错误的用户名和密码.</div>
<!--method必须为"post"-->
<!--th:action="@{/login}" ,
使用动态参数,表单中会自动生成_csrf隐藏字段,用于防止csrf攻击
login: 和登录页面保持一致即可,SpringSecurity自动进行登录认证-->
<form th:action="@{/dologin}" method="post">
<div>
<label for="username">username:</label>
<!--name必须为"username"-->
<input type="text" name="username" placeholder="用户名" id="username"/>
</div>
<div>
<label for="password">password:</label>
<!--name必须为"password"-->
<input type="password" name="password" placeholder="密码" id="password"/>
</div>
<input type="submit" value="登录" />
</form>
</body>
</html>
配置
http.formLogin(formLogin -> formLogin
.loginPage("/dologin").permitAll() //登录页面无需授权即可访问
.usernameParameter("username") //自定义表单用户名参数,默认是username
.passwordParameter("password") //自定义表单密码参数,默认是password
.failureUrl("/dologin?error")
);
这个登录有点类似于aop技术
Handler 处理
认证成功
package com.spring_security.message;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
public class AuthenticationSuccessfulMessage implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
// 获取用户身份信息
Object principal = authentication.getPrincipal();
// 建立返回结果
//转换为json字符串
// 返回响应
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(message);
}
}
认证失败
package com.spring_security.message;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
public class AuthenticationFailedMessage implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,AuthenticationException exception) throws IOException, ServletException {
// 获取异常信息
String localizedMessage = exception.getLocalizedMessage();
// 建立返回结果
//转换为json字符串
// 返回响应
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(message);
}
}
登出成功
package com.spring_security.message;
import com.alibaba.fastjson2.JSON;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
public class LogoutSuccessMessage implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//创建结果对象
//转换成json字符串
//返回响应
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(message);
}
}
权限不够
package com.spring_security.message;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
public class AccessDeniedHandlerMessage implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
//请求未授权的接口
String exceptionMessage = accessDeniedException.getMessage();
//创建结果对象
//转换成json字符串
//返回响应
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(message);
}
}
认证未登录
package com.spring_security.message;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
public class AuthenticationEntryPointMessage implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
//创建结果对象
//转换成json字符串
//返回响应
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(json);
}
}
用户认证信息
基本概念
在Spring Security框架中,SecurityContextHolder、SecurityContext、Authentication、Principal和Credential是一些与身份验证和授权相关的重要概念。它们之间的关系如下:
- SecurityContextHolder:SecurityContextHolder 是 Spring Security 存储已认证用户详细信息的地方。
- SecurityContext:SecurityContext 是从 SecurityContextHolder 获取的内容,包含当前已认证用户的 Authentication 信息。
- Authentication:Authentication 表示用户的身份认证信息。它包含了用户的Principal、Credential和Authority信息。
- Principal:表示用户的身份标识。它通常是一个表示用户的实体对象,例如用户名。Principal可以通过Authentication对象的getPrincipal()方法获取。
- Credentials:表示用户的凭证信息,例如密码、证书或其他认证凭据。Credential可以通过Authentication对象的getCredentials()方法获取。
- GrantedAuthority:表示用户被授予的权限
总结起来,SecurityContextHolder用于管理当前线程的安全上下文,存储已认证用户的详细信息,其中包含了SecurityContext对象,该对象包含了Authentication对象,后者表示用户的身份验证信息,包括Principal(用户的身份标识)和Credential(用户的凭证信息)。
在Controller中获取用户信息
@GetMapping("/userInfo")
@ResponseBody
public Map<String, Object> userInfo() {
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
String username = authentication.getName();//用户名
org.springframework.security.core.userdetails.User user = (org.springframework.security.core.userdetails.User) authentication.getPrincipal();//身份
Object credentials = authentication.getCredentials();//凭证(脱敏)
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();//权限
// 将权限列表转换为字符串列表
List<String> authorities_ = authorities.stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList());
Collection<GrantedAuthority> authorities1 = user.getAuthorities();
// 将权限列表转换为字符串列表
List<String> authorities1_ = authorities1.stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList());
Map<String, Object> message = new LinkedHashMap<>();
message.put("userName", username);
message.put("principal", user);
message.put("credentials", credentials);
message.put("authorities_", authorities_);
message.put("authorities1_", authorities1_);
return message;
}
权限认证
授权
授权管理的实现在SpringSecurity中非常灵活,可以帮助应用程序实现以下两种常见的授权需求:
-
用户-权限-资源:例如张三的权限是添加用户、查看用户列表,李四的权限是查看用户列表
-
用户-角色-权限-资源:例如 张三是角色是管理员、李四的角色是普通用户,管理员能做所有操作,普通用户只能查看信息
基于方法授权
package com.spring_security.controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/*****UTF-8*****
* Description:
* Author: 王 楠
* Date: 2024/6/6 13:11
* Proverbs: 吃的苦中苦,方为人上人
*/
@Controller
@RequestMapping("/perm")
// 开启权限方法注解
@EnableMethodSecurity
public class PermController {
// 权限授权 hasAuthority('r')
@PreAuthorize("hasAuthority('r')")
@GetMapping("/read")
public String read() {
return "read";
}
// 角色授权 hasRole('root')
@PreAuthorize("hasRole('root')")
// @PreAuthorize("hasAuthority('w')")
@GetMapping("/write")
public String write() {
return "write";
}
@PreAuthorize("hasAuthority('x')")
@GetMapping("/execute")
public String execute() {
return "execute";
}
}
在配置文件中添加如下注解
// 开启权限方法注解
@EnableMethodSecurity
// 角色授权 hasRole('root')
@PreAuthorize("hasRole('root')")
// 权限授权 hasAuthority('r')
@PreAuthorize("hasAuthority('r')")
基于request的授权
用户-权限-资源
需求:
- 具有USER_LIST权限的用户可以访问/user/list接口
- 具有USER_ADD权限的用户可以访问/user/add接口
配置权限
SecurityFilterChain
//开启授权保护
http.authorizeRequests(
authorize -> authorize
//具有USER_LIST权限的用户可以访问/user/list
.requestMatchers("/user/list").hasAuthority("USER_LIST")
//具有USER_ADD权限的用户可以访问/user/add
.requestMatchers("/user/add").hasAuthority("USER_ADD")
//对所有请求开启授权保护
.anyRequest()
//已认证的请求会被自动授权
.authenticated()
);
授予权限
DBUserDetailsManager中的loadUserByUsername方法:
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(()->"USER_LIST");
authorities.add(()->"USER_ADD");
/*authorities.add(new GrantedAuthority() {
@Override
public String getAuthority() {
return "USER_LIST";
}
});
authorities.add(new GrantedAuthority() {
@Override
public String getAuthority() {
return "USER_ADD";
}
});*/
更多的例子:Authorize HttpServletRequests :: Spring Security
用户-角色-资源
**需求:**角色为ADMIN的用户才可以访问/user/**路径下的资源
配置角色
SecurityFilterChain
//开启授权保护
http.authorizeRequests(
authorize -> authorize
//具有管理员角色的用户可以访问/user/**
.requestMatchers("/user/**").hasRole("ADMIN")
//对所有请求开启授权保护
.anyRequest()
//已认证的请求会被自动授权
.authenticated()
);
授予角色
DBUserDetailsManager中的loadUserByUsername方法:
return org.springframework.security.core.userdetails.User
.withUsername(user.getUsername())
.password(user.getPassword())
.roles("ADMIN")
.build();
用户-角色-权限-资源
RBAC(Role-Based Access Control,基于角色的访问控制)是一种常用的数据库设计方案,它将用户的权限分配和管理与角色相关联。以下是一个基本的RBAC数据库设计方案的示例:
- 用户表(User table):包含用户的基本信息,例如用户名、密码和其他身份验证信息。
列名 | 数据类型 | 描述 |
---|---|---|
user_id | int | 用户ID |
username | varchar | 用户名 |
password | varchar | 密码 |
varchar | 电子邮件地址 | |
… | … | … |
- 角色表(Role table):存储所有可能的角色及其描述。
列名 | 数据类型 | 描述 |
---|---|---|
role_id | int | 角色ID |
role_name | varchar | 角色名称 |
description | varchar | 角色描述 |
… | … | … |
- 权限表(Permission table):定义系统中所有可能的权限。
列名 | 数据类型 | 描述 |
---|---|---|
permission_id | int | 权限ID |
permission_name | varchar | 权限名称 |
description | varchar | 权限描述 |
… | … | … |
- 用户角色关联表(User-Role table):将用户与角色关联起来。
列名 | 数据类型 | 描述 |
---|---|---|
user_role_id | int | 用户角色关联ID |
user_id | int | 用户ID |
role_id | int | 角色ID |
… | … | … |
- 角色权限关联表(Role-Permission table):将角色与权限关联起来。
列名 | 数据类型 | 描述 |
---|---|---|
role_permission_id | int | 角色权限关联ID |
role_id | int | 角色ID |
permission_id | int | 权限ID |
… | … | … |
在这个设计方案中,用户可以被分配一个或多个角色,而每个角色又可以具有一个或多个权限。通过对用户角色关联和角色权限关联表进行操作,可以实现灵活的权限管理和访问控制。
当用户尝试访问系统资源时,系统可以根据用户的角色和权限决定是否允许访问。这样的设计方案使得权限管理更加简单和可维护,因为只需调整角色和权限的分配即可,而不需要针对每个用户进行单独的设置。
代码地址 https://gitee.com/nan-mu-wang/spring
. | … | … |
- 用户角色关联表(User-Role table):将用户与角色关联起来。
列名 | 数据类型 | 描述 |
---|---|---|
user_role_id | int | 用户角色关联ID |
user_id | int | 用户ID |
role_id | int | 角色ID |
… | … | … |
- 角色权限关联表(Role-Permission table):将角色与权限关联起来。
列名 | 数据类型 | 描述 |
---|---|---|
role_permission_id | int | 角色权限关联ID |
role_id | int | 角色ID |
permission_id | int | 权限ID |
… | … | … |
在这个设计方案中,用户可以被分配一个或多个角色,而每个角色又可以具有一个或多个权限。通过对用户角色关联和角色权限关联表进行操作,可以实现灵活的权限管理和访问控制。
当用户尝试访问系统资源时,系统可以根据用户的角色和权限决定是否允许访问。这样的设计方案使得权限管理更加简单和可维护,因为只需调整角色和权限的分配即可,而不需要针对每个用户进行单独的设置。