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层方法,对数据库进行访问,一旦请求量大了,数据库的压力也大。

另一种方案在下篇介绍。

相关推荐
凯基迪科技23 分钟前
exe软件壳的分类----加密保护壳
java
wuxuanok35 分钟前
Web后端开发-分层解耦
java·笔记·后端·学习
31535669131 小时前
ClipReader:一个剪贴板英语单词阅读器
前端·后端
ladymorgana1 小时前
【Spring Boot】HikariCP 连接池 YAML 配置详解
spring boot·后端·mysql·连接池·hikaricp
kyle~1 小时前
C/C++字面量
java·c语言·c++
neoooo1 小时前
别慌,Java只有值传递——一次搞懂“为啥我改了它还不变”!
java·后端·spring
秋难降1 小时前
Python 知识 “八股”:给有 C 和 Java 基础的你😁😁😁
java·python·c
wuxuanok1 小时前
Web后端开发-请求响应
java·开发语言·笔记·学习
用户7785371836961 小时前
一力破万法:从0实现一个http代理池
后端·爬虫
livemetee1 小时前
spring-ai 1.0.0 (3)交互增强:Advisor 顾问模块
java