springsecurity使用(二)认识rbac模型

springsecurity使用(二)认识rbac模型

一、认识rbac模型基础认知

RBAC(Role-Based Access Control)是一种流行的访问控制模型,它在安全领域中得到广泛应用。Spring Security RBAC是基于RBAC模型实现的一种权限管理解决方案,可用于对Web和企业应用程序进行安全保护。

在Spring Security RBAC模型中,用户、角色和权限是三个主要的实体。每个用户可以拥有一个或多个角色,每个角色可以被分配一个或多个权限。当用户尝试访问受保护的资源时,Spring Security RBAC模型会检查该用户是否具有执行该操作所需的权限。如果用户没有所需的权限,则访问将被拒绝。

下面是Spring Security RBAC模型中的几个关键概念:

  1. 用户(User):代表系统中的一个用户,可以拥有一个或多个角色。
  2. 角色(Role):代表一个或多个权限的集合,可以被分配给一个或多个用户。
  3. 权限(Permission):代表可以执行的操作,例如读取、写入、更新和删除等。
  4. 菜单(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(基于角色的访问控制)模型之外,还有以下几种常见的权限模型:

  1. ABAC(基于属性的访问控制)模型:ABAC通过对用户和资源属性进行评估,以决定用户能否访问资源。例如,用户的国家、部门、机构或IP地址等属性可以用来评估其访问权限。
  2. PBAC(基于策略的访问控制)模型:PBAC基于事先定义的访问策略对用户访问进行限制。例如,通过定义一个"仅允许管理员编辑数据"的策略,可以限制非管理员用户对数据的编辑权限。
  3. ACL(访问控制列表)模型:ACL是一种将权限直接分配给用户或组的模型。这种模型通常适用于小规模系统或少量用户的场景。
  4. MAC(强制访问控制)模型:MAC要求系统定义一个全局的安全策略,该策略限制了用户能够访问的所有对象和操作。在这种模型下,只有满足安全策略的用户才能获得访问权限。

以上是几种常见的权限模型,不同的模型适用于不同的应用场景,具体选择哪种模型需要根据实际情况进行评估和决策。

相关推荐
程序猿麦小七15 分钟前
基于springboot的景区网页设计与实现
java·spring boot·后端·旅游·景区
蓝田~23 分钟前
SpringBoot-自定义注解,拦截器
java·spring boot·后端
theLuckyLong24 分钟前
SpringBoot后端解决跨域问题
spring boot·后端·python
.生产的驴25 分钟前
SpringCloud Gateway网关路由配置 接口统一 登录验证 权限校验 路由属性
java·spring boot·后端·spring·spring cloud·gateway·rabbitmq
小扳29 分钟前
Docker 篇-Docker 详细安装、了解和使用 Docker 核心功能(数据卷、自定义镜像 Dockerfile、网络)
运维·spring boot·后端·mysql·spring cloud·docker·容器
v'sir39 分钟前
POI word转pdf乱码问题处理
java·spring boot·后端·pdf·word
李少兄43 分钟前
解决Spring Boot整合Redis时的连接问题
spring boot·redis·后端
码上一元5 小时前
SpringBoot自动装配原理解析
java·spring boot·后端
枫叶_v8 小时前
【SpringBoot】22 Txt、Csv文件的读取和写入
java·spring boot·后端
杜杜的man8 小时前
【go从零单排】Closing Channels通道关闭、Range over Channels
开发语言·后端·golang