在前面我们讲解了认证中所有常用配置,主要是对 http.formLogin() 和 http.logout() 进行操作。而在配置类中 http.authorizeHttpRequests() 主要是对 url 进行控制,也就是我们所说的授权(访问控制)。
注意:在 Spring Security6 之前,为 http.authorizeRequests() 方法。
下面示例将基于前面“Spring Security6 授权管理准备数工作”章节已经准备好了进行权限管理所需要的数据,来通过一个示例介绍权限管理的基本用法。
假设我们创建了一个名为 SysManagerController 的控制器,该控制器提供了如下功能:
获取系统信息 - /sys/get
新增系统 - /sys/add
更新系统信息 - /sys/update
删除系统信息 - /sys/delete
然而,这些功能仅“系统管理员”才能使用,即拥有“管理员”角色的用户。如果用户不是“管理员”,则不能访问这些功能。
创建 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 接口实现类中,仅仅用来查询用户信息(用来验证用户名和密码是否正确),并没有添加任何权限。
下面将查询用户权限信息,并将权限信息添加到 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 配置类中,添加 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 地址,由于没有登录,将重定向到登录页面,如下图:

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

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

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