0
点赞
收藏
分享

微信扫一扫

Spring Security配合自定义注解实现接口免登录


前言

本demo是基于SpirngBoot2.7.1版本进行开放,如有问题欢迎留言交流!!!

当我们在使用Spring Security实现接口免鉴权,一般方法就是定义一个数组,手动填写需要跳过鉴权的接口地址,就像这样:

// WebSecurityConfig.java

    /**
     * 忽略的接口
     */
    private static final String[] IGNORE_URI = new String[]{
            "/**/login",
            "/**/logout",
            "/**/register",
            "/static/**",
            "/css/**",
            "/js/**",
            "/images/**",
            "/email/send",
            "/refreshToken"
    };

....

// 主要代码
auth.antMatchers(IGNORE_URI).permitAll()

来实现接口免登录请求。因此,在做项目的时候就在想,能不能用注解搞定这个功能,免得每次都要手动写接口地址,所以趁这个机会记录一下


直接上代码

1、先自定义一个注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 接口免登录注解
 *
 * @author jy
 * @version 2024-03-08
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface NotLogin {
}

2、核心代码:实现获取需要免登录接口地址的方法

获取RequestMappingHandlerMapping对象获取接口方法和url信息,其中SpringUtil是hutool工具包中的类

mapping.getHandlerMethods()可以获取所有类中被@RequestMapping标注过的方法的对象,通过这个方法对象,可以获取到该方法的信息,如注解

private Set<String> findNotLoginUrl() {
        RequestMappingHandlerMapping mapping = SpringUtil.getBean(RequestMappingHandlerMapping.class);
        // 这个方法可以获取所有类中被@RequestMapping标注过的方法的对象(Method对象)
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = mapping.getHandlerMethods();
        // 保存需要免登录的url
        Set<String> set = Sets.newHashSet();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) {
            RequestMappingInfo key = entry.getKey();
            HandlerMethod value = entry.getValue();
            NotLogin notLogin = value.getMethodAnnotation(NotLogin.class);
            if (notLogin == null) {
                continue;
            }
            PathPatternsRequestCondition pathPatternsCondition = key.getPathPatternsCondition();
            if (pathPatternsCondition == null) {
                continue;
            }
            set.addAll(pathPatternsCondition.getPatternValues());
        }
        return set;
    }

3、设置免登录url,拿到注解标记的免登录接口后,通过antMatchers设置

@Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        Set<String> notLoginUrl = this.findNotLoginUrl();
        httpSecurity.authorizeHttpRequests(auth -> {
            try {
                auth.antMatchers(IGNORE_URI).permitAll().antMatchers(HttpMethod.OPTIONS).permitAll()
                        .antMatchers(notLoginUrl.toArray(new String[0])).permitAll()
                        .anyRequest()
                        .authenticated()
                        .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                        .and()
                        .csrf().disable()
                        .exceptionHandling()
                        .accessDeniedHandler(new JwtAccessDeniedHandler())
                        .authenticationEntryPoint(new JwtAuthenticationEntryPoint());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
        httpSecurity.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        return httpSecurity.build();
    }

补充:

如果我们想一步到位,直接在类上添加注解直接让类中的接口全部免登录

1、先把注解的标注目标新增支持类

@Target({ElementType.METHOD, ElementType.TYPE})

2、扫描带有@RestController的类,并过滤出含有@NotLogin的注解的类,其中ClassUtil是hutool包中的工具类,包路径根据自己项目的包前缀进行设置

/**
     * 扫描有标注NotLogin类
     * @return
     */
    private Set<Class<?>> scanNotLoginClass(){
        return ClassUtil
                .scanPackageByAnnotation(CommonConstant.PACKAGE_PATH, RestController.class)
                .stream()
                .filter(cls -> cls.isAnnotationPresent(NotLogin.class))
                .collect(Collectors.toSet());
    }

3、加个判断

Spring Security配合自定义注解实现接口免登录_java_04

测试

Spring Security配合自定义注解实现接口免登录_java_05

好的收工,是不是觉得还挺简单的,如果还有什么更好的方法可以交流交流~


举报

相关推荐

spring自定义注解

0 条评论