Spring Security6 权限管理示例

在前面我们讲解了认证中所有常用配置,主要是对 http.formLogin() 和 http.logout() 进行操作。而在配置类中 http.authorizeHttpRequests() 主要是对 url 进行控制,也就是我们所说的授权(访问控制)。

注意:在 Spring Security6 之前,为 http.authorizeRequests() 方法。

下面示例将基于前面“Spring Security6  授权管理准备数工作”章节已经准备好了进行权限管理所需要的数据,来通过一个示例介绍权限管理的基本用法。

示例需求

假设我们创建了一个名为 SysManagerController 的控制器,该控制器提供了如下功能:

  • 获取系统信息 - /sys/get

  • 新增系统 - /sys/add

  • 更新系统信息 - /sys/update

  • 删除系统信息 - /sys/delete

然而,这些功能仅“系统管理员”才能使用,即拥有“管理员”角色的用户。如果用户不是“管理员”,则不能访问这些功能。

具体实现

创建 SysManagerController 控制器

创建 SysManagerController 控制器,该控制器提供的功能仅仅返回一个字符串,如下:

package com.hxstrive.spring_security.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 系统管理相关控制器
 * @author hxstrive.com
 */
@RestController
@RequestMapping("/sys")
public class SysManagerController {

    @RequestMapping("/get")
    public String get(){
        return "获取系统信息";
    }

    @RequestMapping("/add")
    public String add(){
        return "新增系统";
    }

    @RequestMapping("/update")
    public String update(){
        return "更新系统信息";
    }

    @RequestMapping("/delete")
    public String delete(){
        return "删除系统信息";
    }

}

修改自定义 UserDetailsService

在之前创建的自定义 UserDetailsService 接口实现类中,仅仅用来查询用户信息(用来验证用户名和密码是否正确),并没有添加任何权限。

下面将查询用户权限信息,并将权限信息添加到 UserDetails 中,如下:

package com.hxstrive.spring_security.config;

import com.hxstrive.spring_security.service.UserService;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import java.util.List;

/**
 * 自定义实现 UserDetailsService 接口
 * @author hxstrive.com
 */
public class CustomUserDetailsService implements UserDetailsService {
    // 用户服务
    private final UserService userService;

    public CustomUserDetailsService(UserService userService) {
        this.userService = userService;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("loadUserByUsername(String username) :: " + username);

        // 从数据库中加载用户信息
        com.hxstrive.spring_security.model.UserModel user = userService.getByCount(username);
        if(null == user){
            // 用户名不存在。抛出异常
            throw new UsernameNotFoundException("用户名 [" + username + "] 不存在");
        }

        // 看这里,查询用户㣐信息,包含角色和菜单
        // 获取用户权限信息,返回一个字符串集合
        List<String> authorities = userService.getUserAuthorities(user.getId());

        // 创建 UserDetails 对象
        return new User(username, user.getPassword(), AuthorityUtils.createAuthorityList(authorities));
    }

}

修改 Spring Security 配置类

在 Spring Security 配置类中,添加 authorizeHttpRequests() 相关的配置信息,如下:

package com.hxstrive.spring_security.config;

import com.hxstrive.spring_security.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import static org.springframework.security.config.Customizer.withDefaults;

/**
 * Spring Security 配置类
 * @author hxstrive.com
 */
@Configuration
public class SecurityConfig {
    @Resource
    private UserService userService;

    @Bean
    public UserDetailsService userDetailsService() {
        System.out.println("userDetailsService()");
        return new CustomUserDetailsService(this.userService);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        System.out.println("passwordEncoder()");
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        System.out.println("securityFilterChain()");
        // csrfCustomizer.ignoringRequestMatchers(*) 表示所有请求地址都不使用 csrf
        http.csrf(csrfCustomizer -> csrfCustomizer.ignoringRequestMatchers("*"))
        // authorize.anyRequest().authenticated() 表示所有的请求都需要进行身份验证。
        .authorizeHttpRequests(authorize ->
                               authorize.requestMatchers("/sys/*").hasRole("admin")
                               .anyRequest().authenticated()
                              )
        // formLogin 用于配置表单登录功能。
        // permitAll() 表示允许所有用户访问表单登录相关的页面,例如登录页面、登录处理接口等。
        .formLogin(formLoginCustomizer -> formLoginCustomizer.loginPage("/view/login") // 设置登录页面为 /view/login
                   .loginProcessingUrl("/login") // 设置登录处理接口为 /login
                   .failureHandler((request, response, exception) -> {
                       System.out.println("failureHandler()");
                       response.sendRedirect("/view/login?error");
                   })
                   // 设置登录成功自动跳转到 /success 页面,true 表示自动重定向到该页面
                   .successHandler((request, response, authentication) -> {
                       System.out.println("successHandler()");
                       response.sendRedirect("/view/success");
                   }).permitAll()
                  )
        // 用于启用 HTTP 基本认证,withDefaults() 表示使用默认的 HTTP 基本认证配置。
        .httpBasic(withDefaults());

        return http.build();
    }

}

上述代码中,authorizeHttpRequests() 配置如下:

.authorizeHttpRequests(authorize ->
   authorize.requestMatchers("/sys/*").hasRole("admin")
   .anyRequest().authenticated()
)

该配置表示所有以 /sys/ 开头的请求地址,必须拥有编码为“admin”的角色才能被访问。

运行&验证

重启项目,然后通过浏览器访问 http://localhost:8080/hello 地址,由于没有登录,将重定向到登录页面,如下图:

Spring Security6 权限管理示例

输入用户名(lisi)和密码(aaaaaa)登录,然后访问 http://localhost:8080/sys/get 地址,由于 lisi 用户没有系统管理员角色,因此无法访问,如下图:

Spring Security6 权限管理示例

如果使用(zhangsan)账号登录,即拥有管理员权限的账户,则可以正常访问,如下图:

Spring Security6 权限管理示例

注意,在后续章节中将省略掉控制器、启动类等代码展示,将直接给出最核心的配置信息,避免信息太多带来干扰。

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号