您现在的位置是:首页 > 编程 > 

Spring Boot 集成 Spring Security()数据访问权限

2025-07-27 22:05:43
Spring Boot 集成 Spring Security()数据访问权限 Spring Boot 集成 Spring Security()数据访问权限在前面的文章中我们介绍了《Spring Boot 集成 Spring Security(1)认证》和《Spring Boot 集成 Spring Security(2)授权》,这篇博客将介绍如何在 Spring Boot

Spring Boot 集成 Spring Security()数据访问权限

Spring Boot 集成 Spring Security()数据访问权限

在前面的文章中我们介绍了《Spring Boot 集成 Spring Security(1)认证》和《Spring Boot 集成 Spring Security(2)授权》,这篇博客将介绍如何在 Spring Boot 项目中,整合 Spring Security 和 MyBatis-Plus ,轻松实现基于数据库的用户访问控制、权限管理。

推荐框架

基于SpringBoot+Vue前后端分离的Java快速开发框架

项目简介:基于 JDK 17、Spring Boot 、Spring Security 6、JWT、Redis、Mybatis-Plus、Knife4j等构建后端,基于Vue 、Element-Plus 、TypeScript等构建前端的分离单体权限管理系统。

项目地址:

后端:

gitee: .git

gitcode: .git

前端:

gitee: .git

.git

觉着有帮助,给个Star再走呗 搜“Harry技术”,关注我,带你看不一样的人间烟火!

准备工作

新建项目

springboot-security-mysql-example 引入依赖

引入MyBatis-Plus依赖

MyBatis-Plus 是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

注意事项版本 .5.9+ 开始修改为可选依赖,具体查看下文 maven bom 部分。

代码语言:xml复制
  <mybatisplus.version>.5.9</mybatisplus.version>
代码语言:xml复制
    <!-- MyBatis-Plus ;
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-jsqlparser</artifactId>
    </dependency>
代码语言:xml复制
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-bom</artifactId>
                <version>${mybatisplus.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

创建表结构

这里我们定义三张表,来实现用户角权限的操作

代码语言:sql复制
-- 用户表
CREATE TABLE `sys_user` (
	`id` BIGIT OT ULL AUTO_ICREMET COMMET 'ID',
	`username` VARCHAR ( 64 ) DEFAULT ULL COMMET '用户名',
	`password` VARCHAR ( 64 ) DEFAULT ULL COMMET '密码',
	`` CHAR ( 1 ) DEFAULT '0' COMMET '性别 0 男 1 女 2 未知',
	`nick_name` VARCHAR ( 64 ) DEFAULT ULL COMMET '昵称',
	`status` CHAR ( 1 ) DEFAULT '1' COMMET '账号状态 0 禁用 1 启用',
	`valid` IT DEFAULT '1' COMMET '有效状态 0 无效 1 有效',
PRIMARY KEY ( `id` ) 
) EGIE = IODB COMMET = '用户';

ISERT ITO `sys_user` (`id`, `username`, `password`, ``, `nick_name`, `status`, `valid`) VALUES (1, 'admin', '$2a$10$xZdonloiiL6YfoLZv6mrJuvxtD28uHPIKkVDpQKBuZxzMDpTf8uK', '0', '管理员张三', '1', 1);
ISERT ITO `sys_user` (`id`, `username`, `password`, ``, `nick_name`, `status`, `valid`) VALUES (2, 'user', '$2a$10$evM9Sfvu/E.ykWWOf6beTltPvuc6XjwW/qIhagSjlsTfi9l26Ba', '0', '用户李四', '1', 1);

-- 角表
CREATE TABLE `sys_role` (
	`id` BIGIT OT ULL AUTO_ICREMET COMMET 'ID',
	`name` VARCHAR ( 64 ) DEFAULT ULL COMMET '角名',
	`code` VARCHAR ( 64 ) DEFAULT ULL COMMET '密码',
	`status` CHAR ( 1 ) DEFAULT '1' COMMET '状态 0 禁用 1 启用',
	`valid` IT DEFAULT '1' COMMET '有效状态 0 无效 1 有效',
PRIMARY KEY ( `id` ) 
) EGIE = IODB COMMET = '角';

ISERT ITO `sys_role` (`id`, `name`, `code`, `status`, `valid`) VALUES (1, '管理员', 'ROOT', '1', 1);
ISERT ITO `sys_role` (`id`, `name`, `code`, `status`, `valid`) VALUES (2, '普通用户', 'USER', '1', 1);


-- 用户角关系表
CREATE TABLE `sys_user_role` (
	`id` BIGIT OT ULL AUTO_ICREMET COMMET 'ID',
  `user_id` bigint DEFAULT ULL COMMET '用户ID',
  `role_id` bigint DEFAULT ULL COMMET '角ID',
  PRIMARY KEY (`id`) USIG BTREE
) EGIE = IODB COMMET = '用户角关系表';

ISERT ITO `sys_user_role` (`id`, `user_id`, `role_id`) VALUES (1, 1, 1);
ISERT ITO `sys_user_role` (`id`, `user_id`, `role_id`) VALUES (2, 2, 2);

默认设置账户密码12456,在数据库中使用加密后的密码,关于密码加密,可以使用下面的测试方法。

代码语言:java复制
    public static void main(String[] args) {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String result = ("12456");
        // 输出加密后的密码
        println(result);
        // 对比加密后的密码和明文密码
        println(("12456", result));
    }

生成基础代码

这里我用了代码生成器插件,以提高生产效率,想具体了解,可以去上搭建使用。这里就不多说啦

本地代码勾选,使用 mybatis-plus

准备工作到这里基本上就可以了,接下来开始实现从数据库中读取用户角权限

逻辑实现

application.yml配置

代码语言:yaml复制
spring:
  thymeleaf:
    # 设置Thymeleaf模板文件的前缀位置(默认是`src/main/resources/templates`)
    prefix: classpath:/templates/
    # 设置模板文件的后缀(默认是`.html`)
    suffix: .html
    # 设置模板模式(默认是HTML5,Thymeleaf 中为`HTML`)
    mode: HTML
    # 开启模板缓存(开发时建议关闭,生产时开启)
    cache: false
  datasource:
    driver-class-name: jdbc.Driver
    url: jdbc:mysql://127.0.0.1:06/security_data?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: root

#mybatis
mybatis-plus:
  mapper-locati: classpath*:/mapper/**/*.xml
  #实体扫描,多个package用逗号或者分号分隔
  typeAliasesPackage: cn.harry.*.domain
  global-config:
    #数据库相关配置
    db-config:
      #主键类型  AUTO:"数据库ID自增", IPUT:"用户输入ID", ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
      id-type: AUTO
      # 逻辑删除全局属性名(驼峰和下划线都支持)
      logic-delete-field: valid
      logic-delete-value: 0 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 1 # 逻辑未删除值(默认为 0)
    banner: false
  #原生配置
  configuration:
    map-underscore-to-camel-case: true
    cache-enabled: false
    call-setters-on-nulls: true
    jdbc-type-for-null: 'null'
    # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

SecurityConfig 配置

要使用 Spring Security 进行用户认证,我们需要配置 SecurityConfig,并实现自定义的 UserDetailsService 来与数据库中的用户信息进行集成。

代码语言:java复制
/**
 * @author harry
 * @ Harry技术
 */
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(securedEnabled = true) // 开启方法级别的权限控制
@RequiredArgsCtructor
public class SecurityConfig {
    
    // 通过构造函数注入自定义UserDetailsService
    private final UserDetailsService userDetailsService;
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(auth -> auth
                        // 公开访问
                        .requestMatchers("/").permitAll()
                        // 其他接口需认证
                        .anyRequest().authenticated()
                )

                .userDetailsService(userDetailsService)
//                .exceptionHandling(exception -> exception
//                        .authenticationEntryPoint(restAuthenticationEntryPoint)
//                        .accessDeniedHandler(restfulAccessDeniedHandler)
//                )
                // 开启基于表单的登录
                .formLogin(Customizer.withDefaults())

//                // 开启注销功能
//                .logout(Customizer.withDefaults())
//                // 开启 HTTP Basic 认证
//                .httpBasic(Customizer.withDefaults())
//                // 开启 CSRF 防护
//                .csrf(Customizer.withDefaults())
//                // 开启跨域资源共享
//                .cors(Customizer.withDefaults())
        ;

        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        // 使用 BCrypt 进行密码加密
        return new BCryptPasswordEncoder();
    }

自定义 UserDetailsService

想从数据库加载用户信息,就需要创建一个自定义的 UserDetailsService 实现类,它的主要作用:

用户认证:

UserDetailsService 负责从数据源(如数据库、LDAP等)中加载用户特定的安全信息,包括用户名、密码和权限(角)。

Spring Security 使用 UserDetailsService 来验证用户提供的凭据是否正确。

用户授权:

加载用户的权限信息,以便在认证成功后进行授权检查。

权限信息通常包括用户的角(如 ROLE_ADMI, ROLE_USER 等),这些角用于控制用户可以访问的资源和操作。

代码语言:java复制
/**
 * 系统用户认证  service
 *
 * @author harry
 * @ Harry技术
 */
@Slf4j
@Service
@RequiredArgsCtructor
public class UserDetailsServiceImpl implements UserDetailsService {

    private final SysUserMapper sysUserMapper;
    private final SysUserRoleMapper sysUserRoleMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameotFoundException {
        try {
            // 获取登录用户信息
            SysUser user = sysUserMapper.selectByUsername(username);
            // 用户不存在、用户停用 等校验 TODO
            Long useId = user.getId();
            // 获取角
            Set<String> roles = sysUserRoleMapper.listRoleKeyByUserId(useId);
            return new SysUserDetails(user, roles, username);
        } catch (Exception e) {
            ("loadUserByUsername error", e);
        }
        return null;
    }
}

我们根据数据库中的用户信息加载用户,并将角转换为 Spring Security 能识别的格式。我们写一个SysUserDetails类来实现自定义Spring Security 用户对象。

代码语言:java复制
/**
 * 自定义 Spring Security 用户对象
 *
 * @author harry
 * @ Harry技术
 */
@Data
@oArgsCtructor
public class SysUserDetails implements UserDetails {
    private String username;

    private SysUser sysUser;

    private Collection<SimpleGrantedAuthority> authorities;

    public SysUserDetails(SysUser user, Set<String> roles, String username) {
        this.sysUser = user;
        Set<SimpleGrantedAuthority> authorities;
        if (CollectionUtil.isotEmpty(roles)) {
            // 标识角 前面加上 ROLE_
            authorities = roles.stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role)).collect(());
        } else {
            authorities = ();
        }

        this.authorities = authorities;
        this.username = username;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // 返回当前用户的权限
        return authorities;
    }

    @Override
    public String getPassword() {
        return sysUser.getPassword();
    }

    @Override
    public String getUsername() {
        return this.username;
    }

    /**
     * 是否可用 ,禁用的用户不能身份验证
     *
     * @return 是否可用
     */
    @Override
    public boolean isEnabled() {
        return StatusEnums.EABLE.getKey().equals(sysUser.getStatus());
    }
}

创建测试

  • 页面
代码语言:html复制
  <!DOCTYPE html>
  <html lang="en">
  <head>
      <meta charset="UTF-8">
      <title>Title</title>
      <style>
          .content {
              width: 800px;
              height: 800px;
              text-align: center;
              line-height: 100px;
              font-size: 20px;
              flex: 1;
              flex-direction: column;
              display: flex;
              justify-content: center;
              align-items: center;
          }
      </style>
  </head>
  <body>
  <div class="content">
      <!--去登陆 -->
      <a href="/login">去登陆</a>
  
      <!-- admin/info 接口 -->
      <a href="/admin/info">访问 admin/info 接口</a>
  
      <!-- 去首页 -->
      <a href="/user/info">访问 user/info 接口</a>
  
      <!--退出-->
      <a href="/logout">退出</a>
  
  </div>
  </body>
  </html>
  • 接口

改写接口admin/info,并配置@PreAuthorize("hasRole('ROOT')")只有 ADMI 角才能访问

代码语言:java复制
  
  /**
   * @author harry
   * @ Harry技术
   * Spring Boot  集成 Spring Security(2) 授权: 
   */
  @Slf4j
  @RestController
  public class AdminController {
  
  
      @GetMapping("/admin/info")
      @PreAuthorize("hasRole('ROOT')")  // 只有 ADMI 角才能访问
      public SysUserDetails adminInfo() {
          // 获取当前登录的用户信息
          SysUserDetails user = (SysUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
          log.info("当前登录的用户信息:{}", ());
          return user;
      }
  }
  

改写接口user/info,并配置@PreAuthorize("hasRole('USER')")只有 USER 角才能访问

代码语言:java复制
      
  
  @Slf4j
  @RestController
  public class UserController {
  
      @GetMapping("/user/info")
      @PreAuthorize("hasRole('USER')")  // 只有 user 角才能访问
      public SysUserDetails userInfo() {
          // 获取当前登录的用户信息
          SysUserDetails user = (SysUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
          log.info("当前登录的用户信息:{}", ());
          return user;
      }
  }
  
启动测试
  • 1.登录admin账户

访问 admin/info 接口

访问 user/info 接口

  • 2.登录user用户

访问 admin/info 接口

访问 user/info 接口

通过上面的测试用例,通过定义用户和角实体、实现自定义的 UserDetailsService,实现了数据库驱动的用户认证和基于角的授权机制。这种结合方式不仅在安全性上提供了极大的灵活性,也让数据管理变得更加简洁高效。

关注我,在后续的文章中,我们进一步探讨如果使用JWT、OAuth2 等机制、使用Redis作为缓存来强化认证与授权的实现。

示例源码:关注“Harry技术”,回复 security 获取源码地址。

#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格

本文地址:http://www.dnpztj.cn/biancheng/1185644.html

相关标签:无
上传时间: 2025-07-22 10:45:42
留言与评论(共有 8 条评论)
本站网友 mindbridge
22分钟前 发表
map-underscore-to-camel-case
本站网友 广西男科医院
11分钟前 发表
'$2a$10$evM9Sfvu/E.ykWWOf6beTltPvuc6XjwW/qIhagSjlsTfi9l26Ba'
本站网友 叙利亚局势吧
29分钟前 发表
map-underscore-to-camel-case
本站网友 广州月嫂
23分钟前 发表
true cache-enabled
本站网友 期房和现房
10分钟前 发表
可以去上搭建使用
本站网友 中国市场监测中心
27分钟前 发表
/mapper/**/*.xml #实体扫描
本站网友 蛋黄果
4分钟前 发表
`status`