SpringSecurity认证与授权 实现自定义注解

点关注不迷路,欢迎关注点赞评论!

最近在做一个关于认证与授权的功能模块,需要使用自定义注解完成匿名访问的接口放行功能。想必各位大佬都知道或者了解,springsecurity中三个configure方法

image.png

  1. configure(AuthenticationManagerBuilder auth)
  2. configure(HttpSecurity http)
  3. configure(WebSecurity web)
    使用web.ignoring().antMatchers()方法;,可以实现不走 Spring Security 过滤器链
1
2
3
4
5
6
7
java复制代码@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/login");
}
}

一、首先根据官网搭一个基础的环境,加入spring-boot-starter-security和spring-boot-starter-web依赖

修改pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
xml复制代码    <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>demo</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

二、配置基础的SecurityConfig和WebMvcConfig以及登录页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
java复制代码@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private RequestMappingHandlerMapping handlerMapping;

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {

httpSecurity
.authorizeRequests()
.anyRequest()// 所有请求全部需要鉴权认证
.authenticated();
}

@Bean
@Override
public UserDetailsService userDetailsService() {
UserDetails user =
User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();

return new InMemoryUserDetailsManager(user);
}

}
1
2
3
4
5
6
7
8
java复制代码@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
}

}

在templates下添加login.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
html复制代码<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Example </title>
</head>
<body>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have been logged out.
</div>
<form th:action="@{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
</body>
</html>

三、新建controller测试一把

1
2
3
4
5
6
7
8
9
10
11
12
13
14
java复制代码@RestController
@RequestMapping
public class TestController {

@GetMapping("test")
public String test() {
return "直接过滤";
}

@GetMapping("test1")
public String test1() {
return "需要登录";
}
}

四、访问一下localhost:8080/test和test1接口,可以看到会跳转到登录页,说明我们的接口都是被拦截了的

屏幕截图 2021-07-04 140120.png

五、现在我们通过 web.ignoring().antMatchers来把test放行,放行配置如下

1
2
3
4
5
java复制代码    @Override
public void configure(WebSecurity web) throws Exception {
// 此方法可以实现不走 Spring Security 过滤器链
web.ignoring().antMatchers(HttpMethod.GET, "/test");
}

六、再试下test接口访问,直接访问成功

屏幕截图 2021-07-04 141118.png

而test1接口这个时候访问还是需要登录,说明我们的放行配置起到了作用

image.png

这个时候我们又要思考了,当项目越来越大,接口越来越多的时候怎么办呢?难道一直改代码?这样的方式恐怕不妥啊!问题不大,我们现在试一试用注解的方式来放行接口!

思路:把所有带这个注解的方法放行了不就行了吗

开始我们的操作

新建一个IgnoreAuth的注解

1
2
3
4
5
java复制代码@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented //生成文档
public @interface IgnoreAuth {
}

现在有了注解,怎么获取到所有带这个注解的方法呢?

spring提供了RequestMappingHandlerMapping类,可以帮助我们,来获得所有的URL
通过继承(这里就不给大家看源码了,感兴趣的可以自己去看),可以调用getHandlerMethods()来获取

先debug看下获取到的数据是什么样的

1
2
3
4
5
6
java复制代码@Override
public void configure(WebSecurity web) throws Exception {
WebSecurity and = web.ignoring().and();
Map<RequestMappingInfo, HandlerMethod> handlerMethods =
handlerMapping.getHandlerMethods();
}

启动项目,看到handlerMethods中包含了key(请求的类型,请求url)value(具体的方法)

屏幕截图 2021-07-04 144729.png

那现在有了所有的url方法,我们只需要将带有IgnoreAuth注解方法筛选出来,并且直接放行就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
java复制代码handlerMethods.forEach((info, method) -> {
// 带IgnoreAuth注解的方法直接放行
if (!Objects.isNull(method.getMethodAnnotation(IgnoreAuth.class))) {
// 根据请求类型做不同的处理
info.getMethodsCondition().getMethods().forEach(requestMethod -> {
switch (requestMethod) {
case GET:
// getPatternsCondition得到请求url数组,遍历处理
info.getPatternsCondition().getPatterns().forEach(pattern -> {
// 放行
and.ignoring().antMatchers(HttpMethod.GET, pattern);
});
break;
case POST:
info.getPatternsCondition().getPatterns().forEach(pattern -> {
and.ignoring().antMatchers(HttpMethod.POST, pattern);
});
break;
case DELETE:
info.getPatternsCondition().getPatterns().forEach(pattern -> {
and.ignoring().antMatchers(HttpMethod.DELETE, pattern);
});
break;
case PUT:
info.getPatternsCondition().getPatterns().forEach(pattern -> {
and.ignoring().antMatchers(HttpMethod.PUT, pattern);
});
break;
default:
break;
}
....
});
}
});
}

在test方法上打上我们的自定义注解IgnoreAuth

1
2
3
4
5
java复制代码    @IgnoreAuth
@GetMapping("test")
public String test() {
return "直接过滤";
}

写完代码,重启项目,我们再测试下,搞定!
屏幕截图 2021-07-04 141118.png

当然,我这里只是其中一种实现方式,有哪儿不足的地方希望大家能在评论中指出来,谢谢大家!
image.png

写文真不容易,裂开!

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%