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

另一种方案在下篇介绍。

相关推荐
angushine1 小时前
Gateway获取下游最终响应码
java·开发语言·gateway
爱的叹息1 小时前
关于 JDK 中的 jce.jar 的详解,以及与之功能类似的主流加解密工具的详细对比分析
java·python·jar
一一Null1 小时前
Token安全存储的几种方式
android·java·安全·android studio
来自星星的坤1 小时前
SpringBoot 与 Vue3 实现前后端互联全解析
后端·ajax·前端框架·vue·springboot
AUGENSTERN_dc1 小时前
RaabitMQ 快速入门
java·后端·rabbitmq
晓纪同学1 小时前
C++ Primer (第五版)-第十三章 拷贝控制
java·开发语言·c++
小样vvv1 小时前
【源码】SpringMvc源码分析
java
nzwen6662 小时前
Redis学习笔记及总结
java·redis·学习笔记
烛阴2 小时前
零基础必看!Express 项目 .env 配置,开发、测试、生产环境轻松搞定!
javascript·后端·express