本文主要来自于看Java开源项目,方便理解开源项目的代码是怎么实现的,加深自己的基本功。
这个是Spring Security框架中带有的一个注解,一般写在接口方法上,表示这个接口所有人都可以访问
例如
@PostMapping("/login") @PermitAll public CommonResultlogin(@RequestBody User user) { ... }
然后客户端在发送http请求的时候就带有@PermitAll的所有接口都设置成permitAll()方法
这里先写一个获取所有接口中带有@PermitAll的方法
private MultimapgetPermitAllUrlsFromAnnotations() { Multimap result = HashMultimap.create(); // 获得接口对应的 HandlerMethod 集合 RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) applicationContext.getBean("requestMappingHandlerMapping"); Map handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods(); // 获得有 @PermitAll 注解的接口 for (Map.Entry entry : handlerMethodMap.entrySet()) { HandlerMethod handlerMethod = entry.getValue(); if (!handlerMethod.hasMethodAnnotation(PermitAll.class)) { continue; } if (entry.getKey().getPatternsCondition() == null) { continue; } Set urls = entry.getKey().getPatternsCondition().getPatterns(); // 根据请求方法,添加到 result 结果 entry.getKey().getMethodsCondition().getMethods().forEach(requestMethod -> { switch (requestMethod) { case GET: result.putAll(HttpMethod.GET, urls); break; case POST: result.putAll(HttpMethod.POST, urls); break; case PUT: result.putAll(HttpMethod.PUT, urls); break; case DELETE: result.putAll(HttpMethod.DELETE, urls); break; } }); } return result; }
http请求到来的时候将这些接口都设置成permitAll()方法
@Bean protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { // 登出 httpSecurity // 获得 @PermitAll 带来的 URL 列表,免登录 MultimappermitAllUrls = getPermitAllUrlsFromAnnotations(); // 设置每个请求的权限 httpSecurity // 设置 @PermitAll 无需认证 .antMatchers(HttpMethod.GET, permitAllUrls.get(HttpMethod.GET).toArray(new String[0])).permitAll() .antMatchers(HttpMethod.POST, permitAllUrls.get(HttpMethod.POST).toArray(new String[0])).permitAll() .antMatchers(HttpMethod.PUT, permitAllUrls.get(HttpMethod.PUT).toArray(new String[0])).permitAll() .antMatchers(HttpMethod.DELETE, permitAllUrls.get(HttpMethod.DELETE).toArray(new String[0])).permitAll() // 兜底规则,必须认证 .authorizeRequests() .anyRequest().authenticated() ; return httpSecurity.build(); }
这些接口都不设置任何权限,当然这是个Bean方法,还需要使用@Configuration将这个方法的类注入容器,这里就不写了
在开源项目中但凡使用了Spring Security框架的总会在部分接口上看到这个方法
比如
@PostMapping("/create") @Operation(summary = "新增用户") @PreAuthorize("@ss.hasPermission('system:user:create')") public CommonResultcreateUser(@Valid @RequestBody UserCreateReqVO reqVO) { Long id = userService.createUser(reqVO); return success(id); }
很明显这是个创建用户的接口,我们都能看出这个注解的大致意思,就是判断登录的人是否有添加权限
下面来详细说明一下@ss.hasPermission(‘system:user:create’)是什么意思,怎么用的
首先,@PreAuthorize是 Spring Security 内置的前置权限注解,添加在接口方法上,声明需要的权限,实现访问权限的控制。
实现原理:
当 @PreAuthorize 注解里的 Spring EL 表达式返回 false 时,表示没有权限。
而 @PreAuthorize(“@ss.hasPermission(‘system:user:create’)”) 表示调用 Bean 名字为 ss 的 hasPermission(…) 方法,方法参数为"system:user:create" 字符串。
所以你只需要找到在哪儿创建的Bean,并且Bean的名字是ss,就知道这个方法到底是怎么实现的了
果然