基于注解方式实现Spring Security忽略拦截
文章目录
- 1.Spring Security忽略拦截配置
- 2.基于配置文件注入
- 2.1.添加配置
- 2.2.修改Spring Security配置类
- 2.3. 测试
- 3.基于注解的方式过滤接口
- 3.1.添加注解
- 3.2.获取所有使用了@IgnoreWebSecurity注解的接口访问路径
- 3.3.测试
1.Spring Security忽略拦截配置
关于Spring Securite的使用可以参考我写的这篇博客: 【SpringBoot框架篇】16.security整合jwt实现对前后端分离的项目进行权限认证
像这种需要忽略某个接口需要在Spring Security配置类中在代码中写死,非常的不灵活。
2.基于配置文件注入
2.1.添加配置
一般像一些静态资源文件需要过滤掉安全认证,例如图片,.css,.js等静态资源文件,像这种在配置文件中指定比较方便。
application.yml配置
#不需要认证的接口地址
security:
ignore:
get:
- /image/**
post:
all:
添加配置类注入配置的参数
@Configuration
@ConfigurationProperties(prefix = "security.ignore")
public class IgnoreSecurityPropetties {
/**
* 需要忽略的接口路径 不限制请求类型
*/
private List<String> all;
/**
* 需要忽略的Get请求类型接口路径
*/
private List<String> get;
/**
* 需要忽略的Post请求类型接口路径
*/
private List<String> post;
//省略 get,set方法
2.2.修改Spring Security配置类
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private IgnoreSecurityPropetties ignoreSecurityPropetties;
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
String[] all = new String[ignoreSecurityPropetties.getAll().size()];
String[] get = new String[ignoreSecurityPropetties.getGet().size()];
String[] post = new String[ignoreSecurityPropetties.getPost().size()];
ignoreSecurityPropetties.getGet().toArray(get);
ignoreSecurityPropetties.getPost().toArray(post);
ignoreSecurityPropetties.getAll().toArray(all);
if (all.length > 0) {
authorizeRequest.antMatchers(all).permitAll();
}
if (get.length > 0) {
authorizeRequest.antMatchers(HttpMethod.GET, get).permitAll();
}
if (post.length > 0) {
authorizeRequest.antMatchers(HttpMethod.POST, post).permitAll();
}
// 其它接口都要认证
authorizeRequest.anyRequest().authenticated();
}
}
2.3. 测试
@RestController
@RequestMapping("/test")
public class TestIgnoreController {
@GetMapping("/image/{id}")
public String image(@PathVariable String id) {
return id;
}
}
如果从配置文件中删除了过滤的接口名称则访问接口会返回403
3.基于注解的方式过滤接口
3.1.添加注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IgnoreWebSecurity {
/**
* 忽略接口的名称,默认使用Controller访问路径加接口的的访问路径组件
* 使用场景匹配url穿参的动态匹配 例如: /user/{id},像这种需要配置注解值为 /user/*
*/
String value() default "";
}
3.2.获取所有使用了@IgnoreWebSecurity注解的接口访问路径
- 用到了2.2中的IgnoreSecurityPropetties类存放忽略的接口名称
- 用到了2.3中的修改security配置类
@Configuration
public class InitIgnoreWebSecurityConfig implements ApplicationContextAware {
@Autowired
private IgnoreSecurityPropetties ignoreSecurityPropetties;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String, Object> beanMap = applicationContext.getBeansWithAnnotation(RestController.class);
beanMap.forEach((k, v) -> {
//Controllers配置的访问路径
String baseUrl = "";
Class<?> controllerClass = v.getClass();
RequestMapping annotation = AnnotatedElementUtils.findMergedAnnotation(controllerClass, RequestMapping.class);
//如果RequestMapping注解存在,使用RequestMapping里配置的路径名称
if (annotation != null) {
baseUrl = annotation.value().length > 0 ? annotation.value()[0] : "";
}
//判断访问路径前缀是否包含/
if (!baseUrl.startsWith("/")) {
baseUrl = "/" + baseUrl;
}
//获取所有声明的方法
Method[] allMethods = controllerClass.getMethods();
IgnoreWebSecurity ignoreWebSecurity;
PostMapping postMapping;
GetMapping getMapping;
String methodType;
for (Method method : allMethods) {
methodType = "";
//判断方法是否使用忽略权限认证注解
ignoreWebSecurity = AnnotatedElementUtils.findMergedAnnotation(method, IgnoreWebSecurity.class);
if (ignoreWebSecurity != null) {
String url = "";
//当注解没配置接口名称时候使用接口名称(Controller访问路径+接口访问路径)
//目前只适配了PostMapping和GetMapping注解,其它类型请自行扩展
postMapping = AnnotatedElementUtils.findMergedAnnotation(method, PostMapping.class);
if (postMapping != null) {
url = postMapping.value().length > 0 ? postMapping.value()[0] : "";
methodType = "post";
} else {
getMapping = AnnotatedElementUtils.findMergedAnnotation(method, GetMapping.class);
if (getMapping != null) {
url = getMapping.value().length > 0 ? getMapping.value()[0] : "";
methodType = "get";
}
}
//注解如果配置了接口路径则使用注解内的
if (StringUtils.hasText(ignoreWebSecurity.value())) {
url = ignoreWebSecurity.value();
}
if (url.trim().length() > 0) {
url = (baseUrl + "/" + url).replaceAll("/+", "/");
} else {
url = baseUrl;
}
if ("post".equals(methodType)) {
ignoreSecurityPropetties.getPost().add(url);
} else if ("get".equals(methodType)) {
ignoreSecurityPropetties.getGet().add(url);
}
}
}
});
System.out.println("需要忽略的get请求类型接口路径如下" );
for(String get: ignoreSecurityPropetties.getGet()){
System.out.println(get);
}
System.out.println("需要忽略的post请求类型接口路径如下");
for(String post: ignoreSecurityPropetties.getPost()){
System.out.println(post);
}
}
}
启动后会输出
忽略的接口访问路径规则以下文3.3的测试接口为例,
String baseUrl=@RestController控制器的访问路径(/test)
优先级1: String url=baseUrl+IgnoreWebSecurity(注解内值) =/test/css/*
优先级2: String url=baseUrl+接口访问路径(/login) =/test/login
3.3.测试
在需要忽略认证的接口上面添加@IgnoreWebSecurity注解
@RestController
@RequestMapping("/test")
public class TestIgnoreController {
@IgnoreWebSecurity("/css/*")
@GetMapping("/css/{id}")
public String css(@PathVariable String id) {
return id;
}
@IgnoreWebSecurity
@GetMapping("/login")
public String login() {
return "登录成功";
}
}
测试用注解修饰的接口路径,可以正常访问,由此可看配置是正常。