实现步骤
我们想要对每个接口做权限控制
-
先给整个系统所有左侧菜单做一个动态配置功能,前端所有访问后端接口的操作按钮多做为一个子项目新增一条记录,设置一个全局唯一的key
-
每个角色和菜单权限记录关联起来,建一个多对多的表
-
后端每个接口和上文的全局唯一的key对应上加一个注解
@PreAuthorize("hasAuthority('全局唯一的key')")
-
在获取jwt token的时候 根据登录用户id,查找角色,根据角色查找对应菜单权限的全局唯一的key,把key的list添加到
在文件
MyUserDetailsService implements UserDetailsService {
的
UserDetails loadUserByUsername(){}
方法里把全局唯一的key添加到jwt里
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for(;;){
authorities.add(new SimpleGrantedAuthority("全局唯一的key"));
}
重写 UserDetails 接口的
Collection<? extends GrantedAuthority> authorities;
的get方法,把上文的authorities ,return到get里
之后每个用户UserDetails的authorities里都有全局唯一key的List了
- 之后通过token访问接口,会验证接口的注解的全局唯一key是否包含在
每个用户UserDetails的authorities的List里,包含可以访问,否则报异常
自定义异常捕捉
注意要在资源服务捕捉,不是认证服务捕捉
在ResourceServerConfiguration
文件中
/**
* 认证失败处理类
*/
@Autowired
private AuthenticationEntryPointImpl authenticationEntryPoint;
@Override
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
// 权限认证失败处理类
.exceptionHandling().accessDeniedHandler(accessDeniedHandler)
上面配置文件中注入的异常处理类如下
@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, Serializable {
private static final long serialVersionUID = -8970718410437077606L;
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
throws IOException {
Integer code = MyHttpStatus.UNAUTHORIZED;
String msg = MyStringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI());
response.setStatus(200);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().print(msg);
}
}
这样就可以拦截没权限异常,返回自己想返回的统一格式的json了