前言
本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、加个判断
测试
好的收工,是不是觉得还挺简单的,如果还有什么更好的方法可以交流交流~