配置Pom依赖
//父工程
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.6.4version>
parent>
//依赖
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-securityartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
dependencies>
配置application.yaml
spring:
application:
name: springboot-security-test
server:
port: 8899
配置SpringBootApplication主启动
@SpringBootApplication
public class SpingBootApplicationMain {
public static void main(String[] args) {
SpringApplication.run(SpingBootApplicationMain.class, args);
}
}
编写Controller
@RestController
@RequestMapping("/sec")
public class TestController {
@GetMapping("hello")
public String hello(){
return "认证成功";
}
}
修改配置文件中的application.yaml添加Security配置
security: user: name: byz password: 123
启动工程进行验证,访问配置的映射器路径:
进入登陆页面,输入在配置文件中的用户名密码进入
1、修改配置文件,注释掉:
# security:
# user:
# name: byz
# password: 123
2、新建一个配置类
/**
* @Author BaiYZ
* @Program SpringSecurityDemo
* @Description TODO
* @Date 2022-04-14 09:43:31
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//注入密码加密编码器
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder passwordEncoder = (BCryptPasswordEncoder) passwordEncoder();
String password = passwordEncoder.encode("123");
auth.inMemoryAuthentication().withUser("byz").password(password).roles("admin");
}
}
UserDetailService
自定义USerDeatilService
实现UserdetailService
接口
@Service("userDetailsService") //名称必须叫这个
public class MyUserDetailsServiceImpl implements UserDetailsService {
//这里注入数据库查询逻辑,实际校验用户是否存在
//注入mapper进行校验
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
/*
* 1、使用Mapper查询数据库
* 2、判断是否查询到用户
* (这里假定查询结果)
* */
MyUser user = new MyUser();
List<GrantedAuthority> grantedAuthorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admin,user,ROLE_admin");
if (user != null) {
/**
* 从数据库查询到的用户
* 实质上需要返回一个数据库查询到的用户
* 并将其封装成为一个UserDetail对象进行返回,系统会自动校验其中的密码以及用户名信息
*/
return new User("byz", new BCryptPasswordEncoder().encode("123"), grantedAuthorities); //这里USer为UserDetail的子类
} else {
//查询不到就报错
throw new UsernameNotFoundException("用户名不存在!");
}
}
}
设置配置类并且重写配置权限方法configure(AuthenticationManagerBuilder auth)
/**
* @Author BaiYZ
* @Program SpringSecurityDemo
* @Description TODO
* @Date 2022-04-14 09:43:31
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//注入密码编码器
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//设置自定义的USerDetailService逻辑,以及配置密码编码器
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
}
配置类中配置Httpl拦截方法
/**
* 重写http加密校验规则
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
//配置登陆也米娜
.formLogin() //自定义登陆页面 ,这里会调用UserNamePasswordFilter
.loginPage("/user/login")
//登陆访问url地址 由控制器处理
.loginProcessingUrl("/login")
//登陆成功url地址 由控制器处理
.defaultSuccessUrl("/user/success")
//配置路径权限
.and()
.authorizeRequests() //表示配置地址权限访问
//配置以路径匹配来怕配置权限
.antMatchers("/", "/index", "/user/login").permitAll()
//配置指定页面使用角色管理
.antMatchers("/role/admin").hasRole("admin")
.antMatchers("/role/service").hasAnyRole("user,test")
//指定权限管理
.antMatchers("/role/auth").hasAuthority("admin")
.antMatchers("/role/test").hasAnyAuthority("test")
//对请求进行配置 POST Get ....
.anyRequest().authenticated() //所有请求都需要授权
//csrf跨站请求配置
.and()
.csrf().disable()
//配置403 自定义逻辑
//403自定义错误url
.exceptionHandling().accessDeniedPage("/unauth");
}
注入数据源
安全配置类中配置(注入)PersistentTokenRepository
@Bean
public PersistentTokenRepository persistentTokenRepository(){
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
//启动时创建表,创建一次,也可以手动创建(进入这个PersistentTokenRepository获取建表的sql)
jdbcTokenRepository.setCreateTableOnStartup(true);
return jdbcTokenRepository;
}
配置类中
protected void configure(HttpSecurity http) throws Exception {
http
.and()
.rememberMe().tokenRepository(persistentTokenRepository()) //开启RememberMe设置操作数据库对象
.tokenValiditySeconds(60) //设置过期时间
.userDetailsService(userDetailsService); //设置查询数据库的逻辑板 返回UserDetails
//其他配置....
}
页面配置复选框
名称必须叫做remember-me 框架底层设置
<input type="checkbox" name="remember-me"/>
默认的退出登录URL为
/logout
需要自定义就实现LogoutHandler接口
编写基础用户对象(存储数据库中)
/**
* @Author BaiYZ
* @Program SpringSecurityDemo
* @Description 实际的实体类
* @Date 2022-04-15 17:01:52
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
@Serial
private static final long serialVersionUID = 2211L;
private String userName;
private String password;
private String age;
private String birthday;
}
编写SecurityUser用于SpringSecurity
中权限用户封装
/**
* @Author BaiYZ
* @Program SpringSecurityDemo
* @Description 用于鉴权的实体类
* @Date 2022-04-15 17:02:31
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SecurityUser implements UserDetails {
/**
* 当前用户
*/
private transient User currentUserInfo;
/**
* 权限列表
*/
private List<String> permissionValueList;
public SecurityUser(User currentUserInfo) {
if(currentUserInfo != null){
this.currentUserInfo = currentUserInfo;
}
}
/**
* 获取授权列表 GrantedAuthority
* @return Collection extends GrantedAuthority>
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Assert.notNull(this.permissionValueList, "Cannot pass a null GrantedAuthority collection");
//遍历设置权限
Set<GrantedAuthority> setAuthorities = new HashSet<>();
for (String grantedAuthority : this.permissionValueList) {
//权限不为空
if(StringUtils.hasText(grantedAuthority)){
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(grantedAuthority);
setAuthorities.add(simpleGrantedAuthority);
}
}
return setAuthorities;
}
@Override
public String getPassword() {
return null;
}
@Override
public String getUsername() {
return null;
}
@Override
public boolean isAccountNonExpired() {
return false;
}
@Override
public boolean isAccountNonLocked() {
return false;
}
@Override
public boolean isCredentialsNonExpired() {
return false;
}
@Override
public boolean isEnabled() {
return false;
}
}
PassWordEncoder
/**
* @Author BaiYZ
* @Program SpringSecurityDemo
* @Description TODO
* @Date 2022-04-15 14:56:21
*/
@Component
public class DefaultPasswordEncoder implements PasswordEncoder {
@Autowired
BCryptPasswordEncoder bCryptPasswordEncoder;
public DefaultPasswordEncoder() {
}
public DefaultPasswordEncoder(int strength) {
}
/**
* 自定义加密方式 --->> 也可以使用md5加密,返回加密字符串即可
* @param rawPassword 原始密码由Securuty框架传入
* @return
*/
@Override
public String encode(CharSequence rawPassword) {
return bCryptPasswordEncoder.encode(rawPassword);
}
/**
* 比对密码比较的是输入后加密与存储的加密密码比对
* @param rawPassword 框架获取的用户提交的密码
* @param encodedPassword 存储的加密后的密码
* @return bool 真为通过
*/
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
//输入密码加密
String encodeInput = bCryptPasswordEncoder.encode(rawPassword);
return encodedPassword.equals(encodeInput);
}
}
Jwt介绍:
JWT头
- alg:表示签名算法
- typ:令牌类型
{ "alg":"HS256", "typ":"JWT" }
有效载荷 PayLoad(Claims)
- iss:发行人
- exp:到期时间
- sub:主题
- aud:用户
- nbf:在此之前不可用
- iat:发布时间
- jti:jwt id 标识一个JWt
- 私有字段
{ "iss":"xxx", "exp":"222", "sub":"loginedUSer", "nbf":"xxx", "aud":"user", "iat":"xxx", "jti":"xxx", "自定义字段":"value" }
签名哈希
对上面两部分进行签名,使用指定算法生成前面哈希
例子:
HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload),secret)
完整JWt字符串:
拼装结构:
JWTString=Base64(Header).Base64(Payload).签名哈希
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.6.4version>
parent>
<dependency>
<groupId>io.jsonwebtokengroupId>
<artifactId>jjwtartifactId>
<version>0.9.1version>
dependency>
/**
* @Author BaiYZ
* @Program SpringSecurityDemo
* @Description token 管理工具类
* @Date 2022-04-15 15:25:04
*/
@Component("tokenManager")
public class TokenManager {
/**
* token有效期 这里设置60min
*/
private long tokenExpiredTime = 60 * 60 * 1000;
/**
* token密钥
* 一般实际项目中需要实际生成
*/
private String tokenSecrect = "111111";
/**
* 根据Token获取用户名信息
* setSubject(String sub); 设置jwt加密对象
* setExpiration(Date exp); 设置过期时间
* signWith(SignatureAlgorithm alg, String base64EncodedSecretKey); 设置签名算法,签名密钥
* CompressionCodecs.GZIP 进行压缩
*/
public String createToken(String userName){
String token = Jwts.builder()
.setSubject(userName)
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiredTime))
.signWith(SignatureAlgorithm.ES512,tokenSecrect)
.compressWith(CompressionCodecs.GZIP).compact();
return token;
}
//根据用户名获取Token
/**
* Jwts.parser():获取jwt转化器
* setSigningKey(String key):设置签名密钥
* parseClaimsJws(String claimsJws):转化jwt
* getBody():获取body
* @param token 传入token串
* @return 返回信息
*/
public String getUserInfoFromToken(String token){
String userInfo = Jwts.parser()
.setSigningKey(tokenSecrect)
.parseClaimsJws(token)
.getBody()
.getSubject();
return userInfo;
}
public void removeToken(String token){
}
}
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
spring:
redis:
port: 6379
host: localhost
/**
* @Author BaiYZ
* @Program SpringSecurityDemo
* @Description Token退出登陆逻辑
* @Date 2022-04-15 16:11:20
*/
@Component("tokenLogOutHandler")
public class TokenLogOutHandler implements LogoutHandler {
/**
* 注入Token工具类
*/
private TokenManager tokenManager;
/**
* redis模板类
*/
private RedisTemplate redisTemplate;
public TokenLogOutHandler(TokenManager tokenManager, RedisTemplate redisTemplate) {
this.tokenManager = tokenManager;
this.redisTemplate = redisTemplate;
}
/**
* 退出登陆逻辑
* @param request 请求
* @param response 响应
* @param authentication 授权信息封装
*/
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
//1、从header拿到Token
String token = request.getHeader("token");
//2、存在Token
//2.1、移出Token(从Redis删除)
if(token!=null){
tokenManager.removeToken(token);
String userInfoFromToken = tokenManager.getUserInfoFromToken(token);
redisTemplate.delete(userInfoFromToken);
}
//写响应相关操作,返回一个状态xxx
}
}
退出逻辑配置
@Override protected void configure(HttpSecurity http) throws Exception { http .and() .logout() .logoutUrl("/logout") //默认为logout .logoutSuccessHandler(tokenLogOutHandler) //自定义退出成功处理器 .deleteCookies("JSESSIONID") //要删除的Cookies }
AuthenticationEntryPoint
/**
* @Author BaiYZ
* @Program SpringSecurityDemo
* @Description 未授权统一处理
* @Date 2022-04-15 16:32:12
*/
@Component("unAuthenticationEntryPoint")
public class UnAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
//处理未授权逻辑
}
}
未授权统一权限配置:
@Override protected void configure(HttpSecurity http) throws Exception { http //没有权限处理器 .exceptionHandling().authenticationEntryPoint(unAuthenticationEntryPoint) }
/**
* @Author BaiYZ
* @Program SpringSecurityDemo
* @Description 认证过滤器
* @Date 2022-04-15 16:47:42
*/
@Component("tokenLoginFilter")
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
/**
* redis模板类
*/
private RedisTemplate redisTemplate;
/**
* token工具类
*/
private TokenManager tokenManager;
/**
* 权限管理工具类
*/
private AuthenticationManager authenticationManager;
public TokenLoginFilter(RedisTemplate redisTemplate, TokenManager tokenManager, AuthenticationManager authenticationManager) {
this.redisTemplate = redisTemplate;
this.tokenManager = tokenManager;
this.authenticationManager = authenticationManager;
//设置不止用post提交
this.setPostOnly(false);
}
/**
* 重写尝试认证的方法
* 父类会进行调用
*
* @param request 请求
* @param response 响应
* @return Authentication 返回认证封装
* @throws AuthenticationException 认证异常
*/
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
//获取表单提交数据
try {
//从请求中获取用户信息
User user = new ObjectMapper().readValue(request.getInputStream(), User.class);
//交给SpringSecurity管理
return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword(), new ArrayList<>()));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException();
}
}
/**
* AbstractAuthenticationProcessingFilter调用子类attemptAuthentication认证之后
* 成功调用
*
* @param request 请求
* @param response 响应
* @param chain 过滤器链
* @param authResult 认证结果Authentication
* @throws IOException id异常
* @throws ServletException servlet异常
*/
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
//获取认证之后用户信息UserDetail
SecurityUser securityUser = (SecurityUser) authResult.getPrincipal();
//封装token(这里使用用户名生成)
String token = tokenManager.createToken(securityUser.getCurrentUserInfo().getUserName());
//将用户名以及权限列表放入Redis
redisTemplate.opsForValue().set(token, securityUser.getPermissionValueList());
//将Token 返回前端!!!!前端会进行封装放到请求头中
//返回相关页面信息
}
/**
* AbstractAuthenticationProcessingFilter调用子类attemptAuthentication认证之后
* 成功调用
*
* @param request 请求
* @param response 响应
* @param failed 失败的认证异常
* @throws IOException id异常
* @throws ServletException servlet异常
*/
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
//认证失败的逻辑 比如返回页面error json
}
}
配置认证过滤器:
@Override protected void configure(HttpSecurity http) throws Exception { //增加自定义认证过滤器 http.addFilter(tokenLoginFilter) }
/**
* @Author BaiYZ
* @Program SpringSecurityDemo
* @Description 授权过滤器
* @Date 2022-04-15 16:47:15
*/
@Component("tokenAuthenticationFilter")
public class TokenAuthenticationFilter extends BasicAuthenticationFilter {
private TokenManager tokenManager;
private RedisTemplate redisTemplate;
public TokenAuthenticationFilter(AuthenticationManager authenticationManager) {
super(authenticationManager);
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
//获取当前认证成功用户权限信息
UsernamePasswordAuthenticationToken authResult = getAuthentication(request);
//判断存在权限信息,放到权限上下文
if (authResult != null) {
SecurityContextHolder.getContext().setAuthentication(authResult);
}
//放行过滤器
chain.doFilter(request, response);
}
/**
* 从请求中获取解析Token生成UsernamePasswordAuthenticationToken
*
* @param request 请求
* @return UsernamePasswordAuthenticationToken
*/
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
//拿到token
String token = request.getHeader("token");
if (token != null) {
//从token 解析用户名
String username = tokenManager.getUserInfoFromToken(token);
//从redis中获取权限列表
List<String> permissionList = (List<String>) redisTemplate.opsForValue().get("username");
List<GrantedAuthority> collect = null;
if (permissionList != null) {
collect = permissionList.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
}
return new UsernamePasswordAuthenticationToken(username, token, collect);
}
return null;
}
}
配置授权过滤器:
@Override protected void configure(HttpSecurity http) throws Exception { //增加自定义授权过滤器 http.addFilter(tokenAuthenticationFilter) }
/**
* @Author BaiYZ
* @Program SpringSecurityDemo
* @Description 实际查询数据库获取UserDetail
* @Date 2022-04-15 18:54:03
*/
@Service("userDetailService") //名称必须叫这个,否则无法注入
public class UserDetailServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//根据用户名查询数据库,获取Security需要的对象
//返回UserDetail对象
return new SecurityUser();
}
}
配置自定义UserDetailService:
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //增加自定义授权过滤器 auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); }
/**
* @Author BaiYZ
* @Program SpringSecurityDemo
* @Description token 核心配置类
* @Date 2022-04-15 18:22:00
*/
@Configuration
public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 授权失败(为授权)统一处理器
*/
private final UnAuthenticationEntryPoint unAuthenticationEntryPoint;
/**
* 退出处理器
*/
private final TokenLogOutHandler tokenLogOutHandler;
/**
* 认证过滤器
*/
private final TokenLoginFilter tokenLoginFilter;
/**
* 授权过滤器
*/
private final TokenAuthenticationFilter tokenAuthenticationFilter;
/**
* 实际查询数据库获取UserDetail的逻辑
*/
private final UserDetailsService userDetailsService;
@Autowired
public TokenWebSecurityConfig(UnAuthenticationEntryPoint unAuthenticationEntryPoint, TokenLogOutHandler tokenLogOutHandler, TokenLoginFilter tokenLoginFilter,
TokenAuthenticationFilter tokenAuthenticationFilter,UserDetailsService userDetailsService) {
this.unAuthenticationEntryPoint = unAuthenticationEntryPoint;
this.tokenLogOutHandler = tokenLogOutHandler;
this.tokenLoginFilter = tokenLoginFilter;
this.tokenAuthenticationFilter = tokenAuthenticationFilter;
this.userDetailsService = userDetailsService;
}
/**
* 整体配置
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
//没有权限处理器
.exceptionHandling().authenticationEntryPoint(unAuthenticationEntryPoint)
//自定义退出成功处理器
.and()
.logout()
.logoutUrl("/logout") //默认为logout
.addLogoutHandler(tokenLogOutHandler)
.deleteCookies("JSESSIONID") //要删除的Cookies
//配置所有的需要授
.and()
.authorizeRequests()
//这里增加需要hasAuth权限或者需要角色的地址认证
//配置以路径匹配来怕配置权限
// .antMatchers("/", "/index", "/user/login").permitAll()
//
// //配置指定页面使用角色管理
// .antMatchers("/role/admin").hasRole("admin")
// .antMatchers("/role/service").hasAnyRole("user,test")
.anyRequest().authenticated()
//关闭csrf跨域攻击
.and().csrf().disable()
//增加自定义认证过滤器
.addFilter(tokenLoginFilter)
//增加权限过滤器
.addFilter(tokenAuthenticationFilter);
}
/**
* 配置权限验证相关
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailService).passwordEncoder(passwordEncoder());
}
/**
* 设置访问路径相关的
* @param web
* @throws Exception
*/
@Override
public void configure(WebSecurity web) throws Exception {
//设置不进行权限校验的路径
web.ignoring().antMatchers("/");
}
}
1、编写处理器
/**
* @Author BaiYZ
* @Program SpringSecurityDemo
* @Description 登陆成功处理逻辑
* @Date 2022-04-15 15:52:27
*/
@Component("authenticationSuccessHandlerImpl")
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//登陆成功的逻辑
}
}
2、配置到Security配置文件中
@Override
protected void configure(HttpSecurity http) throws Exception {
http.successHandler(authenticationSuccessHandlerImpl);
}
1、编写处理器
/**
* @Author BaiYZ
* @Program SpringSecurityDemo
* @Description 授权失败处理器
* @Date 2022-04-15 15:57:03
*/
@Component("authenticationFailureHandlerImpl")
public class AuthenticationFailureHandlerImpl implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
//授权失败的逻辑
}
}
2、配置到Security配置文件中
@Override
protected void configure(HttpSecurity http) throws Exception {
http.failureHandler(authenticationFailureHandlerImpl);
}
1、编写处理器
/**
* @Author BaiYZ
* @Program SpringSecurityDemo
* @Description 退出登陆处理器
* @Date 2022-04-15 16:02:26
*/
@Component("logoutSuccessHandlerImpl")
public class LogoutSuccessHandlerImpl implements LogoutHandler {
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
//退出登陆的逻辑
}
}
2、配置到Sevurity配置文件中
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.and()
.logout()
.logoutUrl("/logout") //默认为logout
.logoutSuccessHandler(logoutSuccessHandlerImpl) //自定义退出成功处理器
.deleteCookies("JSESSIONID") //要删除的Cookies
}
@Configuration
/**
* 开启全局方法权限注解
* securedEnabled:开启安全注解
* prePostEnabled:前置后置过滤注解
*/
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}
@Secured
适用于方法上,标识当前这个方法是什么样的角色可以访问
/**
* securedEnable测试 开启角色权限
*
* @return
*/
@ResponseBody
@GetMapping("/securedEnabled")
@Secured({"ROLE_test"}) //允许test角色访问
public String securedEnabledTest() {
return "允许访问,这里是 @EnableGlobalMethodSecurity(securedEnabled = true) 注解配置使用@Secure";
}
@PreAuthorize
适用于方法上,可以用权限或者角色,先校验权限,后执行方法 不通过403
/**
* prePostEnabled测试 可以只用权限或者角色,先校验权限,后执行方法 不通过403
*
* @return
*/
@ResponseBody
@GetMapping("/prePostEnabled")
@PreAuthorize("hasAnyAuthority('admin')")
public String prePostEnabled() {
return "允许访问,这里是 @EnableGlobalMethodSecurity(prePostEnabled = true) 注解配置使用 提前校验@PreAuthorize";
}
@PostAuthorize
适用于方法上,有任何权限,先执行方法 后校验权限,不通过403
/**
* prePostEnabled测试 有任何权限,先执行方法 后校验权限
*
* @return
*/
@ResponseBody
@GetMapping("/postEnabled")
@PostAuthorize("hasAnyAuthority('test')")
public String postAuthorize() {
return "允许访问,这里是 @EnableGlobalMethodSecurity(prePostEnabled = true) 注解配置使用 后置校验@PostAuthorize";
}
@PostFilter
适用于方法上,输出匹配的指定值(留下这个其他过滤)
/**
* 权限校验之后,输出匹配的指定值(留下这个其他过滤)
*
* @return
*/
@ResponseBody
@RequestMapping("/postFilter")
@PostFilter("filterObject == 'admin'")
public List<String> getAllListPostFilter() {
ArrayList<String> list = new ArrayList<>();
list.add("admin");
list.add("test");
return list;
}
会输出 admin , test被过滤掉
@PreFilter
适用于方法上,权限校验之后,输出匹配的指定值
/**
* 权限校验之后,输出匹配的指定值
*
* @return
*/
@ResponseBody
@RequestMapping("/preFilter")
@PreFilter("filterObject == 'test'")
public List<String> getAllListPreFilter(@RequestBody List<String> input) {
return input;
}
输入:
[
"test","admin","user","abcd"
]
输出:
[
"test"
]
角色配置中不需要增加“ROLE_”前缀,但是注解中需要增加,数据库中不用增加
public ExpressionInterceptUrlRegistry hasRole(String role) {
return access(ExpressionUrlAuthorizationConfigurer
//这里会传入前缀
.hasRole(ExpressionUrlAuthorizationConfigurer.this.rolePrefix, role));
}
this.rolePrefix
在构造方法中进行设置,如果没有覆盖默认的设置GrantedAuthorityDefaults.class
会使用前缀