紧接上一篇文章,基于Spring Boot 3 + Spring Security6 + JWT + Redis实现接口资源鉴权
系列文章指路👉
系列文章-基于SpringBoot3创建项目并配置常用的工具和一些常用的类
项目源码👉
/shijizhe/boot-test
文章目录
- 1. 修改 UserDetailsService
- 修改取用户的权限列表
- 将权限列表放入UserDetail中
- 2. 新增认证和鉴权异常统一处理程序
- 实现AuthenticationEntryPoint
- 实现AccessDeniedHandler
- 修改Security配置 YaSecurityConfig.securityFilterChain
- 简单测试
- 给方法加权限控制
- 调用测试(事先已登录)
1. 修改 UserDetailsService
采用RBCA模型进行权限控制.
简化后我们有三个表: 用户表、用户角色关联表、角色权限关联表(表结构源码中有:src/main/resources/static/数据结构.sql)
修改取用户的权限列表
<select id="listAuthorityById" resultType="java.lang.String">
SELECT pe.permission_id
FROM ya_user_role ro,
ya_role_permission pe
WHERE ro.role_id = pe.role_id
AND ro.user_id = #{userId}
</select>
将权限列表放入UserDetail中
2. 新增认证和鉴权异常统一处理程序
做这一步的目的是:程序遇到未知的错误,仍可以返回json形式的错误信息,可以帮助排查问题。
实现AuthenticationEntryPoint
/**
* <p>
* 认证异常处理
* </p>
*
* @author Ya Shi
* @since 2024/3/28 16:01
*/
@Component
@Slf4j
public class YaAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
log.error("YaAuthenticationEntryPoint commence 认证过程中遇到异常:{}", authException.toString());
ServletUtils.renderResult(response, new BaseResult<>(ResultEnum.FAILED_UNAUTHORIZED.code, "Security auth failed."));
}
}
实现AccessDeniedHandler
/**
* <p>
* 鉴权异常处理
* </p>
*
* @author Ya Shi
* @since 2024/3/28 16:06
*/
@Component
@Slf4j
public class YaAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
log.error("YaAccessDeniedHandler handle 鉴权过程中遇到异常:{}", accessDeniedException.toString());
ServletUtils.renderResult(response, new BaseResult<>(ResultEnum.FAILED_FORBIDDEN.code, "鉴权失败:" + accessDeniedException.getMessage()));
}
}
修改Security配置 YaSecurityConfig.securityFilterChain
- 允许方法安全授权
@EnableMethodSecurity
- securityFilterChain新增异常统一处理
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler)
.and()
剩余重复代码就不贴了,上篇文章有。
简单测试
给方法加权限控制
@PreAuthorize("hasAuthority('ya_fruit_list')")
@GetMapping("/testApi")
@Operation(summary = "testApi", description = "测试使用-直接返回成功")
@PreAuthorize("hasAuthority('ya_fruit_list')")
public Object testApi(){
String userId = UserAuthUtils.getUserId();
System.out.println(userId);
return BaseResult.success(userId);
}
调用测试(事先已登录)
请求一个没有权限的接口:
@GetMapping("/testApi2")
@Operation(summary = "testApi2", description = "测试使用2-直接返回成功")
@PreAuthorize("hasAuthority('test_test_123456')")
public Object testApi2(){
String userId = UserAuthUtils.getUserId();
System.out.println(userId);
return BaseResult.success(userId);
}