SpringSecurity5 配置接口请求的权限

回到序章

来来来,点这

情形

有一些接口或许要求不需要用户登陆便可以直接请求,还有一些接口是拥有某些权限某些角色才可以访问,这章便是讲述怎么配置的。

效果

啥人分配了啥权限,就能请求啥,没分配则请求不到。

正文

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
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http
// 配置权限
.authorizeRequests()
// 匿名用户可以访问 /test1/a 下所有接口
.antMatchers("/test1/a").hasAnyRole("ANONYMOUS")
// 匿名用户可以访问 /test1/b 下所有接口
.antMatchers("/test1/b").hasAnyAuthority("ROLE_ANONYMOUS")
// 匿名用户可以访问 /test1/c 下所有接口
.antMatchers("/test1/c").anonymous()
// 其他未配置的请求都需要登陆
.anyRequest().authenticated()
// 开启 formLogin 默认配置
.formLogin()
.and()
// 禁用 csrf,默认开启,防止跨站伪造请求
.csrf().disable();
}
}

如注释一般, hasAnyRole("ANONYMOUS") = hasAnyAuthority("ROLE_ANONYMOUS") = anonymous() 意义相等,都是代表着未登录可以访问,但是登陆后便不再可以访问了。

如此,没登陆的用户( 匿名用户 )可以请求到 test1/a 、 /test1/b 、 /test1/c ,登录后这三个接口反而访问不到,只能访问其他的,例如 /test1/d 、 /test2/** 等。

匹配规则的话,是采用了 Ant 风格的路径匹配符,匹配规则如下:

通配符 含义
** 匹配多层路径
* 匹配一层路径
? 匹配任意单个字符

还有一些常用的配置会在下面逐一列出:

常用的权限配置

  • hasAnyRole: 用户拥有某个角色可以请求
  • hasAnyAuthority: 用户拥有某个权限可以请求
  • authenticated: 已经登陆的用户可以请求
  • anonymous: 匿名用户( 没有登陆的用户 )可以请求
  • permitAll: 任何人都可以请求
  • denyAll: 任何人都不能请求
  • rememberMe: 使用记住我方式登陆的用户可以请求
  • fullAuthenticated: 使用记住我方式登陆的用户不能请求
  • hasIpAddress: 指定ip的用户可以请求
  • not: 求反,上列配置的前置使用,代表相反意义
  • access: 使用 Spring EL 表达式,可以参考 官方文档 中的进行折腾。

Spring EL 表达式

这种表达有啥用呢,举个栗子,比如我既想让一个请求可以匿名的时候请求,也可以被拥有 TEST 的角色用户请求,便需要用到了。

1
.antMatchers("/test4/index").access("hasAnyRole('TEST') and isAnonymous()")
  • and
    • 逻辑与
  • or
    • 逻辑或
  • hasRole(String role)
    • 拥有某个角色
    • hasRole(‘admin’)
  • hasAnyRole(String…​ roles)
    • 拥有某些角色
    • hasAnyRole(‘admin’, ‘user’)
  • hasAuthority(String authority)
    • 拥有某个权限
    • hasAuthority(‘read’)
  • hasAnyAuthority(String…​ authorities)
    • 拥有某些权限
    • hasAnyAuthority(‘read’, ‘write’)
  • permitAll
    • 任意用户
  • denyAll
    • 拒绝请求
  • isAnonymous()
    • 匿名用户
  • isRememberMe()
    • 通过记住我登陆的用户
  • isAuthenticated()
    • 登陆的用户
  • isFullyAuthenticated()
    • 不是通过记住我登陆的用户
  • hasPermission(Object target, Object permission)
    • hasPermission(domainObject, ‘read’)
  • hasPermission(Object targetId, String targetType, Object permission)
    • hasPermission(1, ‘com.example.domain.Message’, ‘read’)

角色继承

简单的理解就是 上级角色 拥有完整的 下级角色 请求权限,白话文:下级能请求的,上级也能请求。

假如拷贝下面的配置类:

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
42
43
44
45
46
47
48
49
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Bean
protected UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("admin2").password("{noop}123").roles("user").build());
return manager;
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService())
.and()
.inMemoryAuthentication()
.withUser("admin1").password("{noop}123").roles("admin");
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http
// 配置权限
.authorizeRequests()
.antMatchers("/test2/a").hasRole("admin")
.antMatchers("/test2/b").hasRole("user")
.anyRequest().authenticated()
.and()
.formLogin();
}

// @Bean
// protected RoleHierarchy roleHierarchy() {
// RoleHierarchyImpl hierarchy = new RoleHierarchyImpl();
// hierarchy.setHierarchy("ROLE_admin > ROLE_user");
// return hierarchy;
// }
}

这段配置大概就是创建了俩个用户 admin1 和 admin2

其中 admin1 拥有 admin 的角色,admin2 拥有 user 的角色

拥有 admin 角色的可以请求接口 /test2/a,拥有 user 角色的可以请求接口 /test2/b,但是反过来请求的话则会返回 403( 没有权限 )

角色继承就是让拥有 admin 角色的可以请求 /test2/b

操作的话,先登陆 admin2 ,然后请求 /test2/b ,然后放开注释的代码,重新运行,再登陆 admin2 ,然后请求 /test2/b ,看看俩者有什么差别。

放行静态资源

1
2
3
4
5
6
7
8
@Configuration
public class SecurityWebConfiguration extends WebSecurityConfigurerAdapter {

@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/static/**");
}
}