Spring Boot 实现权限管理(上)

Spring Boot 实现权限管理

Spring Boot 实现权限管理大致有2种方式,一种比较常规且简单的Spring Boot + Spring Security + MyBatis,另一种Spring Boot + Spring Security + JWT。

我们先要明白权限管理的本质,就是一系列挡在控制器前面的过滤器,实现权限管理,也就是设置并实现过滤器的过程。

方案1:Spring Boot + Spring Security + MyBatis

(1)你的数据库要先有sys_user、sys_role和sys_user_role这些表来表示用户和权限的链接。

(2)实现 UserDetailsService:

UserDetailsService 是 Spring Security 框架里的一个核心接口。其作用是从存储(如数据库、LDAP 等)中加载用户信息,为认证和授权流程提供必要的用户数据。

java 复制代码
@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 1. 查询用户(以手机号登录为例)
        SysUser user = userMapper.findByPhoneNumber(phoneNumber)
                .orElseThrow(() -> new UsernameNotFoundException("用户不存在"));

        // 2. 查询用户的角色和权限
        List<GrantedAuthority> authorities = new ArrayList<>();
        //GrantedAuthority 是 Spring Security 框架里的一个接口,它代表了用户所拥有的权限或者角色。在 Spring Security 的认证和授权体系中,GrantedAuthority 扮演着关键角色,主要用于描述用户被授予的权限信息。
        
        // 2 添加角色
        user.getRoles().forEach(role -> {
            authorities.add(new SimpleGrantedAuthority(role.getName()));
        });

        // 3. 返回 Spring Security 的 User 对象
        return new org.springframework.security.core.userdetails.User(
                user.getUsername(),
                user.getPassword(),
                authorities
        );
    }
}

UserDetails 是 Spring Security 框架里的一个核心接口,其主要作用是封装用户的核心信息,这些信息会在认证和授权过程中被使用。Spring Security 在进行用户认证和权限检查时,需要依据 UserDetails 对象里的信息来判断用户是否具备相应的权限。

java 复制代码
package org.springframework.security.core.userdetails;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;

import java.io.Serializable;
import java.util.Collection;

public interface UserDetails extends Serializable {
    // 获取用户的权限集合
    Collection<? extends GrantedAuthority> getAuthorities();
    // 获取用户的密码
    String getPassword();
    // 获取用户名
    String getUsername();
    // 判断用户账户是否未过期
    boolean isAccountNonExpired();
    // 判断用户账户是否未被锁定
    boolean isAccountNonLocked();
    // 判断用户的凭证(如密码)是否未过期
    boolean isCredentialsNonExpired();
    // 判断用户账户是否启用
    boolean isEnabled();
}

(3)配置 Spring Security

在用户登录以后刚刚写的CustomUserDetailsService 是隐式调用的,完全由Spring Boot管理和调用,后续只需要配置SecurityConfig,SecurityConfig便会根据CustomUserDetailsService返回的结果进行拦截,即权限控制。

java 复制代码
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/login", "/public/​**​").permitAll()  // 公开接口
                .requestMatchers("/user/​**​").hasAuthority("user") // 需具体权限
                .anyRequest().authenticated()                         // 其他接口需登录
            )

        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();  // 密码加密
    }
}

现在就可以在整个Spring Boot项目中实现权限管理了。

权限控制方式

scss 复制代码
permitAll():无条件允许任何形式访问,不管你登录还是没有登录。
anonymous():允许匿名访问,也就是没有登录才可以访问。
denyAll():无条件决绝任何形式的访问。
authenticated():只允许已认证的用户访问。
fullyAuthenticated():只允许已经登录或者通过 remember-me 登录的用户访问。
hasRole(String) : 只允许指定的角色访问。
hasAnyRole(String) : 指定一个或者多个角色,满足其一的用户即可访问。
hasAuthority(String):只允许具有指定权限的用户访问hasAnyAuthority(String):指定一个或者多个权限,满足其一的用户即可访问。
hasIpAddress(String) : 只允许指定 ip 的用户访问。

(1)URL 级别权限​:

在 SecurityConfig 中配置:

java 复制代码
.requestMatchers("/admin/​**​").hasRole("ADMIN")
.requestMatchers("/user/​**​").hasAuthority("user")

(2)方法级别权限​​

使用 @PreAuthorize 注解:

java 复制代码
@RestController
@RequestMapping("/api/user")
public class UserController {

    // 需 ADMIN 角色或 user 权限
    @PreAuthorize("hasRole('ADMIN') or hasAuthority('user')")
    @DeleteMapping("/{id}")
    public String deleteUser(@PathVariable Long id) {
        return "删除用户成功";
    }

    // 需 user 权限
    @PreAuthorize("hasAuthority('user')")
    @GetMapping("/{id}")
    public String getUser(@PathVariable Long id) {
        return "用户信息";
    }
}

注意 ​​:需在配置类上添加@EnableGlobalMethodSecurity

java 复制代码
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig {
}

这种方法对性能不友好,因为每一次请求都会触发过滤器去调动mapper层方法,对数据库进行访问,一旦请求量大了,数据库的压力也大。

另一种方案在下篇介绍。

相关推荐
sky_ph9 分钟前
JAVA-GC浅析(一)
java·后端
爱coding的橙子10 分钟前
每日算法刷题Day24 6.6:leetcode二分答案2道题,用时1h(下次计时20min没写出来直接看题解,节省时间)
java·算法·leetcode
LaoZhangAI14 分钟前
Claude Code完全指南:2025年最强AI编程助手深度评测
前端·后端
岁忧15 分钟前
(nice!!!)(LeetCode每日一题)2434. 使用机器人打印字典序最小的字符串(贪心+栈)
java·c++·算法·leetcode·职场和发展·go
LaoZhangAI17 分钟前
FLUX.1 Kontext vs GPT-4o图像编辑全面对比:2025年最全评测指南
前端·后端
LaoZhangAI18 分钟前
2025最全Supabase MCP使用指南:一键连接AI助手与数据库【实战教程】
前端·javascript·后端
天天摸鱼的java工程师24 分钟前
@Autowired 注入失效?
java·后端
sss191s28 分钟前
校招 Java 面试基础题目解析学习指南含新技术实操要点
java·python·面试
编程毕设32 分钟前
【含文档+PPT+源码】基于微信小程序的旅游论坛系统的设计与实现
java·tomcat·旅游
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ34 分钟前
saveOrUpdate 有个缺点,不会把值赋值为null,解决办法
java·开发语言