Bladeren bron

Edit anonymous

tsurumure 10 maanden geleden
bovenliggende
commit
1bf5b60b21

+ 89 - 0
src/main/java/com/backendsys/modules/common/config/security/PermitAllUrlProperties.java

@@ -0,0 +1,89 @@
+package com.backendsys.modules.common.config.security;
+
+import com.backendsys.modules.common.config.security.annotations.Anonymous;
+import org.apache.commons.lang3.RegExUtils;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.regex.Pattern;
+
+@Configuration
+public class PermitAllUrlProperties implements InitializingBean, ApplicationContextAware {
+
+    private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}");
+    private ApplicationContext applicationContext;
+    private List<String> urls = new ArrayList<>();
+
+    public String ASTERISK = "*";
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+
+        System.out.println("afterPropertiesSet:");
+
+        // 将整个项目所有的bean对象都拿出来
+        RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
+        // 获取每一个方法,获取url和类与方法对应的信息
+        Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
+
+        // info代表每一个url对象
+        map.keySet().forEach(info -> {
+//          获取类和方法
+            HandlerMethod handlerMethod = map.get(info);
+
+            // 获取方法上边的注解 替代path variable 为 *
+//            AnnotationUtils.findAnnotation()为第三方的依赖,进行判断 一个方法上有没有注解
+            Anonymous method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Anonymous.class);
+
+            if (method != null) {
+                System.out.println("method:");
+                System.out.println(method);
+                System.out.println(info);
+            }
+
+////          ifPresent()方法就是会返回一个boolean类型值,如果对象不为空则为真,如果为空则为false
+//            Optional.ofNullable(method).ifPresent(anonymous ->
+//                    //获取url的Set集合,一个方法可能对应多个url
+//                    info.getPatternsCondition().getPatterns()
+//                        .forEach(
+//                            url ->
+//                                urls.add(RegExUtils.replaceAll(String.valueOf(url), PATTERN, ASTERISK))
+//                        ));
+
+            // 获取类上边的注解, 替代path variable 为 *
+            Anonymous controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Anonymous.class);
+            Optional.ofNullable(controller).ifPresent(anonymous -> info.getPatternsCondition().getPatterns()
+                .forEach(url -> urls.add(RegExUtils.replaceAll(String.valueOf(url), PATTERN, ASTERISK))));
+        });
+
+    }
+
+
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        this.applicationContext = applicationContext;
+    }
+
+    public List<String> getUrls()
+    {
+        return urls;
+    }
+
+    public void setUrls(List<String> urls)
+    {
+        this.urls = urls;
+    }
+
+}

+ 24 - 4
src/main/java/com/backendsys/modules/common/config/security/SecurityConfig.java

@@ -1,15 +1,20 @@
 package com.backendsys.modules.common.config.security;
 
 import cn.hutool.core.util.ArrayUtil;
+//import com.backendsys.modules.common.config.security.filter.AnonymousFilter;
 import com.backendsys.modules.common.config.security.filter.CaptchaVerficationFilter;
 import com.backendsys.modules.common.config.security.filter.JwtAuthenticationFilter;
 import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
 import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
 import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
 import org.springframework.security.config.http.SessionCreationPolicy;
 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@@ -18,13 +23,14 @@ import org.springframework.security.web.SecurityFilterChain;
 import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
 
 @Configuration
-@EnableWebSecurity // 开启网络安全注解
+@EnableWebSecurity
 @RequiredArgsConstructor
-//@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
+// @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
 @EnableMethodSecurity(securedEnabled = true)
 public class SecurityConfig {
 
     private final JwtAuthenticationFilter jwtAuthenticationFilter;
+//    private final AnonymousFilter anonymousFilter;
 
     @Bean
     public PasswordEncoder getPw() {
@@ -56,11 +62,24 @@ public class SecurityConfig {
     // Spring-Security 更新日志文档 (升级版本是否对语法有影响):
     // https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/config/web/server/ServerHttpSecurity.html
 
+    @Autowired
+    private PermitAllUrlProperties permitAllUrl;
+
     @Bean
     public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 
         String [] whitelist = getWhitelist();
 
+
+
+
+
+        System.out.println(permitAllUrl.getUrls());
+
+
+
+
+
         // 路径授权
         http
             // 禁用csrf(防止跨站请求伪造攻击)
@@ -88,7 +107,9 @@ public class SecurityConfig {
                     )
                     .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
             )
-            .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
+//            .addFilterBefore(anonymousFilter, UsernamePasswordAuthenticationFilter.class)
+            .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
+            ;
 
             // 使用无状态session,即不使用session缓存数据
 //            .logout()
@@ -127,7 +148,6 @@ public class SecurityConfig {
         return http.build();
     }
 
-
     // 跨域资源配置
     //@Bean
     //public CorsConfigurationSource corsConfigurationSource() {

+ 12 - 0
src/main/java/com/backendsys/modules/common/config/security/annotations/Anonymous.java

@@ -0,0 +1,12 @@
+package com.backendsys.modules.common.config.security.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+//@Target(ElementType.METHOD)
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Anonymous {
+}

+ 50 - 0
src/main/java/com/backendsys/modules/common/config/security/filter/AnonymousFilter.java

@@ -0,0 +1,50 @@
+//package com.backendsys.modules.common.config.security.filter;
+//
+//import com.backendsys.modules.common.config.security.annotations.Anonymous;
+//import jakarta.servlet.http.HttpServletRequest;
+//import jakarta.servlet.http.HttpServletResponse;
+//import jakarta.servlet.FilterChain;
+//import jakarta.servlet.ServletException;
+//
+//import org.springframework.stereotype.Component;
+//import org.springframework.web.filter.OncePerRequestFilter;
+//
+//
+//import java.io.IOException;
+//import java.util.Map;
+//
+//@Component
+//public class AnonymousFilter extends OncePerRequestFilter {
+//
+//    @Override
+//    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
+//        throws ServletException, IOException {
+//
+//        // 检查是否有@Anonymous注解,如果有,则允许访问
+//        if (hasAnonymousAnnotation(request)) {
+//            filterChain.doFilter(request, response);
+//        } else {
+//            // 继续执行Spring Security的过滤器链
+//            filterChain.doFilter(request, response);
+//        }
+//    }
+//
+//
+//    private boolean hasAnonymousAnnotation(HttpServletRequest request) {
+//
+////        Anonymous method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Anonymous.class);
+//
+////        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
+////        HandlerMethod handlerMethod = (HandlerMethod) attributes.getAttribute(HandlerMethod.class.getName(), RequestAttributes.SCOPE_REQUEST);
+////
+////        // 获取当前请求的 HandlerMethod
+////        System.out.println("handlerMethod: " + handlerMethod);
+////        System.out.println("------------------------------------");
+////        if (handlerMethod != null) {
+////            // 检查方法是否有@Anonymous注解
+////            return handlerMethod.getMethodAnnotation(Anonymous.class) != null;
+////        }
+//        return false;
+//    }
+//
+//}

+ 15 - 0
src/main/java/com/backendsys/modules/common/config/security/utils/SecurityUtil.java

@@ -9,6 +9,7 @@ import io.jsonwebtoken.Claims;
 import io.jsonwebtoken.Jwts;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Service;
 
 import javax.crypto.SecretKey;
 import javax.crypto.spec.SecretKeySpec;
@@ -16,6 +17,18 @@ import java.nio.charset.StandardCharsets;
 import java.util.Base64;
 import java.util.List;
 
+/**
+ * 权限工具类:
+ * SecurityUtil.hasPermission("3.2.1")
+ * SecurityUtil.hasPermissions(Arrays.asList("3.2.1", "3.2.2"))
+ * SecurityUtil.hasPermissions(Arrays.asList("3.2.1", "3.2.2"), MatchType.OR)
+ *
+ * 权限注解:
+ * @PreAuthorize("@sr.hasPermission('3.2.1')")
+ * @PreAuthorize("@sr.hasPermissions(T(java.util.Arrays).asList('3.2.1', '3.2.2'))")
+ */
+
+@Service("sr")
 public class SecurityUtil {
 
     private static final String SECRET_KEY = "452948404D635166546A576E5A7134743777217A25432A462D4A614E64526755";
@@ -58,6 +71,7 @@ public class SecurityUtil {
 
     /**
      * 判断是否具备权限 (单个)
+     * - SecurityUtil.hasPermission("3.2.1")
      */
     public static Boolean hasPermission(String permission) {
         SecurityUserInfo userInfo = getUserInfo();
@@ -68,6 +82,7 @@ public class SecurityUtil {
      * 判断是否具备用户权限 (多个) (默认 AND)
      * - SecurityUtil.hasPermissions(Arrays.asList("3.2.1", "3.2.2"))
      * - SecurityUtil.hasPermissions(Arrays.asList("3.2.1", "3.2.2"), MatchType.OR)
+     * - 注意:权限储存在Token中,更新权限需要重新登录
      */
     public static Boolean hasPermissions(List<String> permissions, MatchType matchType) {
         SecurityUserInfo userInfo = getUserInfo();

+ 3 - 0
src/main/java/com/backendsys/modules/system/controller/SysUserV2Controller.java

@@ -1,5 +1,6 @@
 package com.backendsys.modules.system.controller;
 
+import com.backendsys.modules.common.config.security.annotations.Anonymous;
 import com.backendsys.modules.common.config.security.utils.SecurityUtil;
 import com.backendsys.modules.common.enums.MatchType;
 import com.backendsys.modules.common.utils.Result;
@@ -20,8 +21,10 @@ public class SysUserV2Controller {
     @Autowired
     private SysUserV2Service sysUserV2Service;
 
+    @Anonymous
     @Operation(summary = "获得系统用户详情")
     @GetMapping("/api/v2/system/user/getUserDetail")
+//    @PreAuthorize("@sr.hasPermissions(T(java.util.Arrays).asList('3.2.1', '3.2.2'))")
     public Result getUserDetail(@Parameter(description = "用户ID") Long user_id) {
 
 //        System.out.println(tokenUtil.getUserId());