@PreAuthorize 和 @PostAuthorize是SpringSecurity中常用的两个注解,简单了解一下他们的用法吧!
开启验证
package com.bill.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @author : [email protected]
* @create : 10-20-2020 15:27:16
* @description : SpringSecurity配置类
* @since : v1.0
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 基于内存的方式构建两个用户,user/123456,admin/123456
auth.inMemoryAuthentication()
.passwordEncoder(passwordEncoder())
.withUser("admin")
.password(passwordEncoder().encode("123456"))
.roles("admin");
auth.inMemoryAuthentication()
.passwordEncoder(passwordEncoder())
.withUser("user")
.password(passwordEncoder().encode("123456"))
.roles("normal");
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
@PreAuthorize注解
package com.bill.controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author : [email protected]
* @create : 10-20-2020 15:22:13
* @description : HomeController
* @since : v1.0
*/
@Controller
@RequestMapping("/hello")
public class HelloController {
@GetMapping("/")
@ResponseBody
public String sayHello() {
return "Hello, spring security.";
}
@GetMapping("/helloNormal")
@ResponseBody
@PreAuthorize("hasAnyRole('normal')")
public String helloNormal() {
return "Hello, normal.";
}
@GetMapping("/helloAdmin")
@ResponseBody
@PreAuthorize("hasAnyRole('admin')")
public String helloAdmin() {
return "Hello, admin";
}
}
当@EnableGlobalMethodSecurity(prePostEnabled = true)开启的时候,@PreAuthorize注解生效,支持SpringEL表达式,
// 只要有其中一个权限即可访问
@PreAuthorize("hasAnyRole("admin", "normal")")
// 同时满足条件才可以访问
@PreAuthorize("hasRole('admin') AND hasRole('normal')")
@PostAuthorize
@PostAuthorize 注解使用并不多,在方法执行后再进行权限验证,适合验证带有返回值的权限,Spring EL 提供返回对象能够在表达式语言中获取返回的对象returnObject。
当@EnableGlobalMethodSecurity(prePostEnabled = true)的时候,@PostAuthorize可以使用:
@GetMapping("/helloUser")
@PostAuthorize("returnObject != null && returnObject.username == authentication.name")
public User helloUser() {
Object pricipal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
User user;
if ("anonymousUser".equals(pricipal)) {
user = null;
} else {
user = (User) pricipal;
}
return user;
}
内置表达式:
表达式 | 备注 |
---|---|
hasRole([role]) | 如果有当前角色, 则返回 true(会自动加上 ROLE_ 前缀) |
hasAnyRole([role1, role2]) | 如果有任一角色即可通过校验, 返回true,(会自动加上 ROLE_ 前缀) |
hasAuthority([authority]) | 如果有指定权限, 则返回 true |
hasAnyAuthority([authority1, authority2]) | 如果有任一指定权限, 则返回true |
principal | 获取当前用户的 principal 主体对象 |
authentication | 获取当前用户的 authentication 对象, |
permitAll | 总是返回 true, 表示全部允许 |
denyAll | 总是返回 false, 代表全部拒绝 |
isAnonymous() | 如果是匿名访问, 返回true |
isRememberMe() | 如果是remember-me 自动认证, 则返回 true |
isAuthenticated() | 如果不是匿名访问, 则返回true |
isFullAuthenticated() | 如果不是匿名访问或remember-me认证登陆, 则返回true |
hasPermission(Object target, Object permission) | |
hasPermission(Object target, String targetType, Object permission) |
@Secured
当@EnableGlobalMethodSecurity(securedEnabled = true)的时候,@Secured可以使用。
@GetMapping("/helloUser")
@Secured({"ROLE_admin", "ROLE_normal"})
public String helloUser() {
return "hello, user";
}
拥有normal或者admin角色的用户都可以访问helloUser()方法。另外需要注意的是这里 匹配的字符串需要添加前缀“ROLE_“,如果我们要求,只有同时拥有admin & normal的用户才能访问helloUser()方法,这时候@Secured就无能为力了。