紧接上一篇文章,基于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_idFROM ya_user_role ro,ya_role_permission peWHERE ro.role_id = pe.role_idAND 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 {@Overridepublic 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 {@Overridepublic 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);}