授权

认证

身份认证,就是判断一个一个用户是否为合法用户的处理过程。Spring Security中支持所中不同方式的认证。

授权

授权,即访问控制,控制水能访问那些资源。提前设计好系统权限规则,给认证的用户分配某一个资源的权限,用户根据自己所具有的权限,去执行相应的操作。

用户在认证成功之后会将当前登陆用户信息保存到Authentication对象中,Authentication对象中有一个getAuthorities()方法,用来返回当前登陆用户具备的权限信息,当需要进行权限判断时,就会根据集合返回权限信息调用相应方法进行判断。

我们针对授权可以是“基于角色权限管理”和“基于资源权限管理”,从设计层面上来说,角色和权限是两个完全不同的东西

权限是一些具体的操作,角色则是某些权限的集合。

  • 基于角色权限设计:用户-角色-资源,返回的就是用户的角色

  • 基于资源权限设计就是:用户-权限-资源三者关系,返回就是用户的权限。

  • 基于角色和资源权限设计就是:用户-角色-权限-资源,返回统称为权限。

在Spring Security中,角色和权限处理方式基本上是一致的。唯一区别就是会自动给角色添加ROLE_前缀,而权限则不会自动添加。

权限管理策略

SpringSecurity中为我们提供了两种权限管理策略:

  • 基于过滤器的权限管理(FilterSecurityInterceptor):基于过滤器的权限管理主要是用来拦截HTTP请求,拦截下来之后,根据HTTP请求地址进行权限校验。

  • 基于AOP的权限管理(MethodSecurityInterceptor):基于AOP权限管理主要是用来处理方法级别的权限问题。放需要调用某一个方法时,通过AOP将操作拦截下来,然后判断用户是否具备相关权限。

方法

说明

hasAuthority(String authority)

当前用户是否具备指定权限

hasAnyAuthority(String... authorities)

当前用户是否具备指定权限中的任意一个

hasRole(String role)

当前用户是否具备指定角色

hasAnyRole(String... roles)

当前用户是否具备指定角色中的任意一个

permitAll()

放行所有请求

denyAll()

拒绝所有请求

isAnonymous()

当前用户是否是一个匿名用户

isAuthenticated

当前用户是否已经认证成功

isRememberMe()

当前用户是否通过Remember-Me自动登陆

getAuthorities

当前用户是否既不是匿名用户也不同通过Remember-Me自动登陆

hasPermission(Object target, Object permission)

当前用户是否具备指定目标的指定权限信息

hasPermission(Object targetId, String targetType, Object permission)

当前用户是否具备指定目标的制定权限信息

基于请求的授权

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
    httpSecurity.authorizeHttpRequests(authorizeHttpRequests ->
            authorizeHttpRequests
                    .requestMatchers("/admin/role/**").hasRole("ADMIN") // admin/role/** 路径下的请求,需要 ADMIN 角色
                    .requestMatchers("/admin/auth/**").hasAnyAuthority("ADMIN:API")// admin/auth/** 路径下的请求,需要 ADMIN:API 权限
                    .requestMatchers("/user/role/**").hasRole("USER")    // user/role/** 路径下的请求,需要 USER 角色
                    .requestMatchers("/user/auth/**").hasAuthority("USER:API")   // user/auth/** 路径下的请求,需要 USER:API 权限
                    .requestMatchers("/login", "/welcome").permitAll()  // 所有用户都可以访问
                    .anyRequest().authenticated()
    );
    httpSecurity.formLogin(formLogin -> formLogin.loginPage("/login")
            .defaultSuccessUrl("/welcome"));
    httpSecurity.csrf(AbstractHttpConfigurer::disable).cors(withDefaults());
    return httpSecurity.build();
}
/**
 * 配置用户信息服务
 */
@Bean
public UserDetailsService userDetailsService() {
    InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
    UserDetails user1 = User.withUsername("admin").password("{noop}123").roles("ADMIN").authorities("ADMIN:API").build();
    UserDetails user2 = User.withUsername("user").password("{noop}123").roles("USER").authorities("USER:API").build();
    inMemoryUserDetailsManager.createUser(user1);
    inMemoryUserDetailsManager.createUser(user2);
    return inMemoryUserDetailsManager;
}

基于方法注解的鉴权

在Spring Security6版本中@EnableGlobalSecurity被弃用,取而代之的是@EnableMethedSecurity,默认情况下,会激活pre-post注解,并在内部使用AuthorizationManager。

  • PostAuthorize

/**
 * PostAuthorize  注解的作用是在方法执行后再进行权限验证,这样可以拿到方法的返回值,然后再进行权限验证
 * returnObject 表示方法的返回值
 *
 * @param id 用户id
 * @return String
 */
@PostAuthorize("returnObject.startsWith('Rol1e')")
@GetMapping("/stu/role1/{id}")
public String stuAuth1(@PathVariable("id") String id) {
    return "Role Hello student!, id=" + id;
}
  • PostFilter

/**
 * PostFilter 注解的作用是在方法执行后再进行权限验证,这样可以拿到方法的返回值,然后可以对返回值进行过滤,然后再进行权限验证
 * 例如:下面的例子中,只有返回值的长度大于2的才能访问
 * @return String
 */
@PostFilter("filterObject.length() > 2")
@GetMapping("/stu/role2/{id}")
public List<String> stuAuth2() {
    List<String> list = new ArrayList<>();
    list.add("张三");
    list.add("李四");
    list.add("王五");
    list.add("赵小名");
    return list;
}
  • PostAuthorize:

/**
 * PostAuthorize  注解的作用是在方法执行后再进行权限验证,这样可以拿到方法的返回值,然后再进行权限验证
 * returnObject 表示方法的返回值
 *
 * @param id 用户id
 * @return String
 */
@PostAuthorize("returnObject.startsWith('Role')")
@GetMapping("/stu/role1/{id}")
public String stuAuth1(@PathVariable("id") String id) {
    return "Role Hello student!, id=" + id;
}
  • PreFilter

/**
 * PreFilter 注解的作用是在方法执行前进行权限验证,这样可以拿到方法的参数,然后再进行权限验证
 * 例如:下面的例子中,只有参数的长度大于2的才能访问, filterTarget 表示过滤的目标,这里是id
 *
 * @param id 用户id
 * @return String
 */
@PreFilter(value = "filterObject.length() > 2", filterTarget = "id")
@PostMapping("/stu/role3/{id}")
public List<String> stuAuth3(@RequestBody List<String> id) {
    List<String> list = new ArrayList<>();
    list.add("张三");
    list.add("李四");
    list.add("王五");
    list.add("赵小名");
    return list;
}

动态权限

最后更新于

这有帮助吗?