springsecurity使用(二)认识rbac模型
一、认识rbac模型基础认知
RBAC(Role-Based Access Control)是一种流行的访问控制模型,它在安全领域中得到广泛应用。Spring Security RBAC是基于RBAC模型实现的一种权限管理解决方案,可用于对Web和企业应用程序进行安全保护。
在Spring Security RBAC模型中,用户、角色和权限是三个主要的实体。每个用户可以拥有一个或多个角色,每个角色可以被分配一个或多个权限。当用户尝试访问受保护的资源时,Spring Security RBAC模型会检查该用户是否具有执行该操作所需的权限。如果用户没有所需的权限,则访问将被拒绝。
下面是Spring Security RBAC模型中的几个关键概念:
- 用户(User):代表系统中的一个用户,可以拥有一个或多个角色。
- 角色(Role):代表一个或多个权限的集合,可以被分配给一个或多个用户。
- 权限(Permission):代表可以执行的操作,例如读取、写入、更新和删除等。
- 菜单(Menu)
辅助表
:代表系统中的一个菜单项,可以被分配给一个或多个角色,用户可以根据其角色访问相应的菜单项。
在Spring Security RBAC模型中,通常还有一个授权服务(Authorization Service),用于执行访问控制决策。授权服务负责将用户、角色和权限映射到安全策略中,以便在运行时进行访问控制。
二、认识rbac模型数据库建表
数据建表:
建表语句:
sql
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (
`id` int(10) NOT NULL,
`permName` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`permTag` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '请求url',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`id` int(10) NOT NULL,
`roleName` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`roleDesc` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
DROP TABLE IF EXISTS `sys_role_permission`;
CREATE TABLE `sys_role_permission` (
`role_id` int(10) NULL DEFAULT NULL,
`perm_id` int(10) NULL DEFAULT NULL,
INDEX `FK_Reference_3`(`role_id`) USING BTREE,
INDEX `FK_Reference_4`(`perm_id`) USING BTREE,
CONSTRAINT `FK_Reference_3` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `FK_Reference_4` FOREIGN KEY (`perm_id`) REFERENCES `sys_permission` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` int(10) NOT NULL,
`username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`realname` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`password` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`createDate` date NULL DEFAULT NULL,
`lastLoginTime` date NULL DEFAULT NULL,
`enabled` int(5) NULL DEFAULT NULL,
`accountNonExpired` int(5) NULL DEFAULT NULL,
`accountNonLocked` int(5) NULL DEFAULT NULL,
`credentialsNonExpired` int(5) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
`user_id` int(10) NULL DEFAULT NULL,
`role_id` int(10) NULL DEFAULT NULL,
INDEX `FK_Reference_1`(`user_id`) USING BTREE,
INDEX `FK_Reference_2`(`role_id`) USING BTREE,
CONSTRAINT `FK_Reference_1` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `FK_Reference_2` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
三、具体代码实现
1、实现UserDetailsService接口
UserDetailsService
是Spring Security框架中的一个接口,用于从用户存储源(如数据库、LDAP、内存等)中加载用户详细信息。它是实现用户认证的关键组件之一。
UserDetailsService接口定义了一个方法loadUserByUsername
,该方法根据用户名获取用户的详细信息,并返回一个实现了UserDetails接口的对象。UserDetails接口代表了用户的详细信息,包括用户名、密码、角色等。
在Spring Security中,您可以自定义实现UserDetailsService接口,以适配特定的用户存储源。例如,您可以编写一个类实现UserDetailsService接口,并在该类中使用JPA或Hibernate查询数据库来获取用户信息。
2、MemberDetailsService.java
java
@Component
public class MemberDetailsService implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
UserEntity userEntity = userMapper.findByUsername(userName);
if (userEntity == null) {
return null;
}
List<PermissionEntity> userListpermission = userMapper.findPermissionByUsername(userName);
ArrayList<GrantedAuthority> grantedAuthorities = new ArrayList<>();
userListpermission.forEach((p -> {
grantedAuthorities.add(new SimpleGrantedAuthority(p.getPermTag()));
}));
userEntity.setAuthorities(grantedAuthorities);
return userEntity;
}
}
3、实现Spring Security的配置类
Spring Security的配置类,用于配置用户认证和授权的相关信息。 首先,该配置类使用了@EnableWebSecurity
注解,表示启用Web安全功能。然后,继承了WebSecurityConfigurerAdapter
类,该类提供了一些方便的方法来配置Web安全。
在该配置类中,有几个重要的方法需要理解。
(1)、configure(AuthenticationManagerBuilder auth)
方法用于配置认证管理器。在该方法中,调用auth.userDetailsService(memberDetailsService)
指定了一个自定义的UserDetailsService实现类memberDetailsService
来加载用户详细信息。同时使用匿名内部类实现了一个PasswordEncoder接口,将密码转为MD5形式进行比对。这样,当进行用户认证时,会将用户提供的密码进行MD5加密后再与数据库中存储的密码进行比对。
(2)、configure(HttpSecurity http)
方法用于配置HTTP请求的安全性。在该方法中,首先创建了一个ExpressionUrlAuthorizationConfigurer对象authorizeRequests
,用于配置URL的访问权限。然后通过调用permissionMapper.findAllPermission()
方法获取所有权限列表,并为每个权限添加了对应的URL规则和权限要求。最后设置了登录页面为/login
并禁用了跨站请求伪造防护(CSRF)。
(3)、passwordEncoder()
方法声明了一个NoOpPasswordEncoder
实例作为密码编码器。在较新版本的Spring Security中,不再推荐使用该密码编码器,但这里使用此方法是为了解决一个错误(There is no PasswordEncoder mapped for the id "null")。
总结来说
,这段代码主要配置了用户认证和授权的相关信息。通过自定义的UserDetailsService实现类加载用户详细信息,配置密码编码器进行密码比对,配置URL的访问权限,并设置登录页面和禁用CSRF防护。
SecurityConfig.java
java
package com.example.mayikttest.config;
import com.example.mayikttest.enity.PermissionEntity;
import com.example.mayikttest.mapper.PermissionMapper;
import com.example.mayikttest.utils.MD5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private PermissionMapper permissionMapper;
@Autowired
private MemberDetailsService memberDetailsService;
/**
* 新增Security 授权的账户
*
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(memberDetailsService).passwordEncoder(new PasswordEncoder() {
@Override
public String encode(CharSequence rawPassword) {
return MD5Util.encode((String) rawPassword);
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
// md5 传递密码 传递密码 MD5 加密 ===DB中密码 密码输入正确的
String rawPass = MD5Util.encode((String) rawPassword);
boolean result = rawPass.equals(encodedPassword);
return result;
}
});
}
@Override
protected void configure(HttpSecurity http) throws Exception {
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry
authorizeRequests = http.authorizeRequests();
// 1.需要查询到所有的权限
List<PermissionEntity> allPermission = permissionMapper.findAllPermission();
allPermission.forEach((p -> {
// 将该规则添加
authorizeRequests.antMatchers(p.getUrl()).hasAnyAuthority(p.getPermTag());
}));
// 可以允许login 不被拦截
authorizeRequests.antMatchers("/login").permitAll()
// 设置自定义登录页面
.antMatchers("/**").fullyAuthenticated().and().formLogin()
.loginPage("/login").and().csrf().disable();
}
/**
* There is no PasswordEncoder mapped for the id "null"
* 原因:升级为Security5.0以上密码支持多中加密方式,恢复以前模式
*
* @return
*/
@Bean
public static NoOpPasswordEncoder passwordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}
}
其它
Spring项目中除了RBAC(基于角色的访问控制)模型之外,还有以下几种常见的权限模型:
- ABAC(基于属性的访问控制)模型:ABAC通过对用户和资源属性进行评估,以决定用户能否访问资源。例如,用户的国家、部门、机构或IP地址等属性可以用来评估其访问权限。
- PBAC(基于策略的访问控制)模型:PBAC基于事先定义的访问策略对用户访问进行限制。例如,通过定义一个"仅允许管理员编辑数据"的策略,可以限制非管理员用户对数据的编辑权限。
- ACL(访问控制列表)模型:ACL是一种将权限直接分配给用户或组的模型。这种模型通常适用于小规模系统或少量用户的场景。
- MAC(强制访问控制)模型:MAC要求系统定义一个全局的安全策略,该策略限制了用户能够访问的所有对象和操作。在这种模型下,只有满足安全策略的用户才能获得访问权限。
以上是几种常见的权限模型,不同的模型适用于不同的应用场景,具体选择哪种模型需要根据实际情况进行评估和决策。