SpringSecurity学习笔记
1)什么是SpringSecurity:
Spring Security是一个功能强大且高度可定制的,主要负责为Java程序提供声明式的 身份验证和访问控制 的安全框架。
Spring Security的底层主要是 基于 Spring AOP 和 Servlet 过滤器 来实现安全控制,它提供了全面的安全解决方案,同时授权粒度可以在 Web请求级和方法调用级 来处理身份确认和授权。
2)SpringSecurity和Shiro的区别:
1.Shiro
Apache 旗下的轻量级权限控制框架
轻量级。Shiro 主张的理念是把复杂的事情变简单。针对对性能有更高要求的互联网应用有更好表现
通用性
不局限于 Web 环境,可以脱离 Web 环境使用
在 Web 环境下一些特定的需求需要手动编写代码定制。
2.Spring Security
Spring Security 是 Spring 家族中的一个安全管理框架
和 Spring 无缝整合
全面的权限控制
专门为 Web 开发而设计
旧版本不能脱离 Web 环境使用
新版本对整个框架进行了分层抽取,分成了核心模块和 Web 模块。单独
引入核心模块就可以脱离 Web 环境。重量级
3)SpringSecurity的核心组件:
Authentication(身份验证):封装用户的身份,通常使用其子类UsernamePasswordAuthenticationToken来封装用户名和密码进行身份验证。Authorization(授权):用于控制哪些用户具有哪些权限来访问应用程序中的特定资源。UserDetailsService:用于加载用户的真实信息(通常在mysql中获取数据),后续提供给AuthenticationManager跟Authentication进行身份验证。UserDetails:表示应用程序中的用户详细信息,如用户名、密码和权限等真实数据,UserDetailsService查询到数据的封装对象。AuthenticationManager:负责验证认证对象,并返回一个已认证的对象,通常包括使用多个 AuthenticationProvider。AuthenticationProvider:用于对用户进行身份验证,支持不同类型的身份验证机制,如用户名/密码、LDAP、OAuth 等。GrantedAuthority:表示用户所拥有的权限,通常由角色或权限字符串表示。SecurityContext:保存关联到当前执行线程的安全信息,包括已认证的主体和其权限,已经通过认证的Authentication对象载体。SecurityContextHolder:提供对当前线程的 SecurityContext 的访问,其中包含经过身份验证的用户的安全信息,统一管理SecurityContext对象,相当于SecurityContext对象的工厂类。FilterChain:用于处理传入的 HTTP 请求,Spring Security 将其用于应用一系列安全过滤器来执行身份验证和授权逻辑。SecurityConfigurerAdapter:用于配置 Spring Security 的 Java 配置适配器,允许用户自定义安全配置。AuthenticationEntryPoint:在用户试图访问受保护资源但未经过身份验证时触发的策略。LogoutHandler:处理用户登出时执行的操作,如清除会话、撤销令牌等。RememberMeServices:支持“记住我”功能,用于在用户下次访问应用程序时自动进行身份验证。PasswordEncoder:用于加密和验证密码,以确保安全存储用户凭据。SessionManagement:用于管理用户的会话,如设置最大并发会话数、会话创建和销毁事件等。CsrfTokenRepository:用于防止 CSRF(跨站请求伪造)攻击的令牌存储库。SecurityFilterChain:定义了一系列安全过滤器,用于保护特定的 URL 路径或请求模式。
4)SpringSecurity的工作流程:
SpringSecurity的原理其实就是一个过滤器链,内部包含了提供各种功能的过滤器。

| 过滤器 | 过滤器作用 | 默认是否加载 |
|---|---|---|
ChannelProcessingFilter | 过滤请求协议 HTTP 、HTTPS | NO |
WebAsyncManagerIntegrationFilter | 将 WebAsyncManger 与 SpringSecurity 上下文进行集成 | YES |
SecurityContextPersistenceFilter | 在处理请求之前,将安全信息加载到 SecurityContextHolder 中 | YES |
HeaderWriterFilter | 处理头信息加入响应中 | YES |
CorsFilter | 处理跨域问题 | NO |
CsrfFilter | 处理 CSRF 攻击 | YES |
LogoutFilter | 处理注销登录 | YES |
OAuth2AuthorizationRequestRedirectFilter | 处理 OAuth2 认证重定向 | NO |
Saml2WebSsoAuthenticationRequestFilter | 处理 SAML 认证 | NO |
X509AuthenticationFilter | 处理 X509 认证 | NO |
AbstractPreAuthenticatedProcessingFilter | 处理预认证问题 | NO |
CasAuthenticationFilter | 处理 CAS 单点登录 | NO |
OAuth2LoginAuthenticationFilter | 处理 OAuth2 认证 | NO |
Saml2WebSsoAuthenticationFilter | 处理 SAML 认证 | NO |
UsernamePasswordAuthenticationFilter | 处理表单登录 | YES |
OpenIDAuthenticationFilter | 处理 OpenID 认证 | NO |
DefaultLoginPageGeneratingFilter | 配置默认登录页面 | YES |
DefaultLogoutPageGeneratingFilter | 配置默认注销页面 | YES |
ConcurrentSessionFilter | 处理 Session 有效期 | NO |
DigestAuthenticationFilter | 处理 HTTP 摘要认证 | NO |
BearerTokenAuthenticationFilter | 处理 OAuth2 认证的 Access Token | NO |
BasicAuthenticationFilter | 处理 HttpBasic 登录 | YES |
RequestCacheAwareFilter | 处理请求缓存 | YES |
AwareRequestFilter | 包装原始请求 | YES |
JaasApiIntegrationFilter | 处理 JAAS 认证 | NO |
RememberMeAuthenticationFilter | 处理 RememberMe 登录 | NO |
AnonymousAuthenticationFilter | 配置匿名认证 | YES |
OAuth2AuthorizationCodeGrantFilter | 处理OAuth2认证中授权码 | NO |
SessionManagementFilter | 处理 session 并发问题 | YES |
ExceptionTranslationFilter | 处理认证/授权中的异常 | YES |
FilterSecurityInterceptor | 处理授权相关 | YES |
SwitchUserFilter | 处理账户切换 | NO |
认证流程图:

根据认证流程我们能够了解到认证过程是在UsernamePasswordAuthenticationFilter过滤器中完成的:
- 认证过滤器会将前端输入的账号密码封装成
UsernamePasswordAuthenticationToken,并交给AuthenticationManager进行认证处理; AuthenticationManager会调用AuthenticationProvider进行数据的一致性校验;AuthenticationProvider会调用UserDetailsService的loadUserByUsername()方法获取真实数据UserDetails;AuthenticationProvider会将UsernamePasswordAuthenticationToken跟UserDetails进行数据一致性检验,并且添加权限;- 校验通过会返回
AuthenticationToken给UsernamePasswordAuthenticationFilter; UsernamePasswordAuthenticationFilter将AuthenticationToken设置认证上下文中,表示完成认证。
授权流程图:

5)入门:
引入依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>配置账号密码:
spring: security: user: name: admin password: 123456网页输入
http://localhost:8888/login:
6)自定义认证:
在真实项目中我们肯定是不会这样去使用的,目前比较流行的认证有3种:
- 登录后服务器保存session;
- 登陆后服务器返回给前端token;
- AUTH2.0的方式认证。
我们就采取token的方式来自定义认证方式吧;
具体流程:

6.1)自定义登录/登出接口:
@RestController
@RequestMapping("sys")
public class SysController {
@Resource
private AuthenticationManager authenticationManager;
@PostMapping("login")
public Result<String> login(@RequestBody LoginUser user) {
System.out.println("自定义登录接口" + JSONUtil.toJsonStr(user));
//1.将前端传入的数据封装成功SpringSecurity的认证对象
MultiAuthenticationToken authenticationToken = new MultiAuthenticationToken(user.getUserName(), user.getPassword(), null, 1);
//2.手动调用认证
Authentication authenticate = authenticationManager.authenticate(authenticationToken);
if (authenticate == null) {
return Result.fail("登录失败");
}
//生成token
String token = IdUtil.fastSimpleUUID();
//保存到缓存中
Cache.TOKEN_CACHE.put(token, (UserInfo) authenticate.getDetails());
//返回token
return Result.success(token);
}
@PostMapping("logout")
public Result<Boolean> logout(HttpServletRequest request) {
//判断是否有token
String authToken = request.getHeader("AuthToken");
if (StrUtil.isBlank(authToken)) {
throw new RuntimeException("AuthToken为空");
}
//获取当前用户
MultiAuthenticationToken authentication = (MultiAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
return Result.result(-1, false, "未登录");
}
//删除token缓存
Cache.TOKEN_CACHE.remove(authToken);
return Result.success(true);
}
}登录对象:
@Data
public class LoginUser {
private String userName;
private String password;
}6.2)自定义多功能Authentication:
自定义一个既可以通过密码认证又可以短信认证的Authentication对象。
/**
* @description: 多功能认证
* @Title: MultiAuthenticationToken
* @Author xlw
* @Package com.xlw.test.spring_security_demo.config
* @Date 2024/9/20 22:12
*/
public class MultiAuthenticationToken extends AbstractAuthenticationToken {
private String principal;
private String credentials;
private String smsCode;
/**
* 登录类型,1:用户名密码登录,2:手机号登录
*/
private int loginType;
//认证前调用
public MultiAuthenticationToken(String principal, String credentials, String smsCode, int loginType) {
super(null);
this.principal = principal;
this.credentials = credentials;
this.smsCode = smsCode;
this.loginType = loginType;
setAuthenticated(false);
}
//确定认证时调用
public MultiAuthenticationToken(String principal, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
super.setAuthenticated(true);
}
@Override
public String getCredentials() {
return credentials;
}
@Override
public String getPrincipal() {
return principal;
}
public String getSmsCode() {
return smsCode;
}
public int getLoginType() {
return loginType;
}
@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
Assert.isTrue(!isAuthenticated, "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
super.setAuthenticated(false);
}
@Override
public void eraseCredentials() {
super.eraseCredentials();
this.credentials = null;
}
}6.3)自定义AuthenticationProvider:
验证用户登录数据的入口。
/**
* @description: 多功能认证校验器
* @Title: MultiAuthenticationProvider
* @Author xlw
* @Package com.xlw.test.spring_security_demo.config
* @Date 2024/9/20 22:22
*/
public class MultiAuthenticationProvider implements AuthenticationProvider {
@Resource
private UserDetailsService userDetailsService;
@Resource
private PasswordEncoder passwordEncoder;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (authentication == null) {
throw new AuthException("获取认证信息失败");
}
if (!(authentication instanceof MultiAuthenticationToken)) {
throw new AuthException("认证对象不正确");
}
MultiAuthenticationToken authToken = (MultiAuthenticationToken) authentication;
//获取真实的用户数据
UserDetails userDetails = userDetailsService.loadUserByUsername(authToken.getPrincipal());
if (userDetails == null) {
throw new AuthException("用户名不存在");
}
if (authToken.getLoginType() == 1) {
//密码登录
if (!passwordEncoder.matches(authToken.getCredentials(), userDetails.getPassword())) {
throw new AuthException("用户名或者密码不正确");
}
} else if (authToken.getLoginType() == 2) {
//短信登录
String code = Cache.SMS_CACHE.get(authToken.getPrincipal());
if (StrUtil.isBlank(code)) {
throw new AuthException("短信验证码已过期");
}
if (!Objects.equals(code, authToken.getSmsCode())) {
throw new AuthException("短信验证码不正确");
}
}
//设置详情
authToken.setDetails(userDetails);
return authToken;
}
@Override
public boolean supports(Class<?> authentication) {
return MultiAuthenticationToken.class.isAssignableFrom(authentication);
}
}6.4)自定义UserDetailsService:
获取用户真实数据的类。
/**
* @description:
* @Title: AuthServiceImpl
* @Author xlw
* @Package com.xlw.test.spring_security_demo.service.impl
* @Date 2024/9/20 21:58
*/
@Service
public class AuthServiceImpl implements UserDetailsService {
/**
* 按用户名加载用户
*
* @param username 用户名
* @return {@link UserDetails }
* @throws UsernameNotFoundException 未找到用户名异常
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//模拟从数据库取数据
User user = Cache.DATABASE.get(username);
if (user == null) {
return null;
}
UserInfo userInfo = new UserInfo();
BeanUtil.copyProperties(user, userInfo, false);
return userInfo;
}
}6.5)自定义UserDetails:
封装用户的真实数据类
@NoArgsConstructor
@AllArgsConstructor
@Data
public class UserInfo implements UserDetails {
private String username;
private String password;
private String realName;
private Integer age;
private Set<GrantedAuthority> authorities;
private boolean accountNonExpired;
private boolean accountNonLocked;
private boolean credentialsNonExpired;
private boolean enabled;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public boolean isAccountNonExpired() {
return accountNonExpired;
}
@Override
public boolean isAccountNonLocked() {
return accountNonLocked;
}
@Override
public boolean isEnabled() {
return enabled;
}
@Override
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
}6.6)自定义PasswordEncoder:
对用户密码进行加密、匹配类
public class MD5PasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence rawPassword) {
String pwd = DigestUtil.md5Hex(rawPassword.toString());
return pwd;
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return Objects.equals(encodedPassword, encode(rawPassword));
}
}6.7)自定义认证失败处理器:
需要认证访问,却还未认证的访问请求进行失败处理。
public class LoginFailHandler implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=utf-8");
Result<String> result = Result.fail(authException.getMessage());
PrintWriter writer = response.getWriter();
JSONConfig config = new JSONConfig();
config.setIgnoreNullValue(false);
config.setDateFormat(DatePattern.NORM_DATETIME_MS_PATTERN);
try {
writer.println(JSONUtil.toJsonStr(result, config));
} finally {
writer.flush();
writer.close();
}
}
}6.8)自定义token认证过滤器:
通过header携带的token检验该次请求能否认证。
public class TokenAuthFilter extends OncePerRequestFilter {
@Override
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authToken = request.getHeader("AuthToken");
if (StrUtil.isNotBlank(authToken)) {
UserInfo userInfo = Cache.TOKEN_CACHE.get(authToken);
if (userInfo != null) {
MultiAuthenticationToken authenticationToken = new MultiAuthenticationToken(userInfo.getUsername(), Collections.emptySet());
//认证,相当于保存到ThreadLocal中供后续的拦截器使用,没有这一步说明认证失败
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
//放行,交给后面的过滤器处理
filterChain.doFilter(request, response);
}
}6.9)配置security:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private UserDetailsService authService;
@Override
protected void configure(HttpSecurity http) throws Exception {
//配置权限管理,白名单
http.authorizeHttpRequests()
.antMatchers(Cache.PATH_WHITELIST)
.permitAll()
.anyRequest()
.authenticated() //别的请求都需要认证
.and()
.exceptionHandling()
.authenticationEntryPoint(new LoginFailHandler()); //设置认证失败处理器
//添加认证过滤器
http.addFilterBefore(new TokenAuthFilter(), UsernamePasswordAuthenticationFilter.class);
//禁用csrf和cors
http.cors().and().csrf().disable();
//禁用原始的表单登录
http.formLogin().disable();
//禁用原始的登出
http.logout().disable();
//禁用session
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
/**
* 没有这个启动项目会报错
* 认证管理器
*
* @return {@link AuthenticationManager }
* @throws Exception 例外
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/**
* 配置验证器,加密等
*
* @param auth 认证
* @throws Exception 例外
*/
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(multiAuthenticationProvider()) //注入多功能认证器
.userDetailsService(authService) //注入用户详情服务
.passwordEncoder(passwordEncoder()); //注入密码加密器
}
@Bean
public AuthenticationProvider multiAuthenticationProvider() {
return new MultiAuthenticationProvider();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new MD5PasswordEncoder();
}
}7)鉴权:
在SpringSecurity中有角色和权限两种鉴权方式;
- 定义角色要有
ROLE_前缀,如:ROLE_ADMIN、ROLE_SYSTEM等。 - 定义权限没有特别规定,但是推荐
模块:功能,如dept:list、dept:add等。
SpringSecurity有两种鉴权方式:编程式、注解式。
首先我们将以上代码加入权限功能:
修改UserDetailsService:
@Service
public class AuthServiceImpl implements AuthService, UserDetailsService {
/**
* 按用户名加载用户
*
* @param username 用户名
* @return {@link UserDetails }
* @throws UsernameNotFoundException 未找到用户名异常
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//模拟从数据库取数据
User user = Cache.DATABASE.get(username);
if (user == null) {
return null;
}
UserInfo userInfo = new UserInfo();
BeanUtil.copyProperties(user, userInfo, false);
//权限集合
Set<GrantedAuthority> authorities = new HashSet<>();
//添加角色
List<String> roles = Cache.USER_ROLE_DATABASE.get(userInfo.getUsername());
if (CollectionUtil.isNotEmpty(roles)) {
for (String role : roles) {
GrantedAuthority authority = new SimpleGrantedAuthority(role);
authorities.add(authority);
}
}
//添加权限
List<String> permissions = Cache.USER_PERMISSIONS_DATABASE.get(userInfo.getUsername());
if (CollectionUtil.isNotEmpty(permissions)) {
for (String permission : permissions) {
GrantedAuthority authority = new SimpleGrantedAuthority(permission);
authorities.add(authority);
}
}
//设置用户拥有的权限
userInfo.setAuthorities(authorities);
return userInfo;
}
}修改TokenAuthFilter:
为MultiAuthenticationToken设置权限。
public class TokenAuthFilter extends OncePerRequestFilter {
@Override
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authToken = request.getHeader("AuthToken");
if (StrUtil.isNotBlank(authToken)) {
UserInfo userInfo = Cache.TOKEN_CACHE.get(authToken);
if (userInfo != null) {
//设置权限
MultiAuthenticationToken authenticationToken = new MultiAuthenticationToken(userInfo.getUsername(), userInfo.getAuthorities());
//认证,相当于保存到ThreadLocal中供后续的拦截器使用,没有这一步说明认证失败
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
//放行,交给后面的过滤器处理
filterChain.doFilter(request, response);
}
}7.1)编程式鉴权:
支持4中鉴权方式:

**hasAnyAuthority()**:只要有任何一种权限即可访问;
//权限认证
http.authorizeHttpRequests().antMatchers("/sys/test").hasAnyAuthority("sys:list");
我们看到没有权限确实被拦截了但是却没有返回内,我们可以自定义AccessDeniedHandler来对鉴权失败的请求进行处理:
public class NotAccessHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
accessDeniedException.printStackTrace();
response.setStatus(HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED);
response.setContentType("application/json;charset=utf-8");
PrintWriter writer = response.getWriter();
try {
JSONConfig config = new JSONConfig();
config.setIgnoreNullValue(false);
config.setDateFormat(DatePattern.NORM_DATETIME_MS_PATTERN);
Result<String> result = new Result(HttpStatus.HTTP_PROXY_AUTH, null, "无权访问");
writer.println(JSONUtil.toJsonStr(result, config));
} finally {
writer.flush();
writer.close();
}
}
}处理器生效配置:
//配置权限管理,白名单
http.authorizeHttpRequests()
.antMatchers(Cache.PATH_WHITELIST)
.permitAll()
.anyRequest()
.authenticated() //别的请求都需要认证
.and()
.exceptionHandling()
.authenticationEntryPoint(new LoginFailHandler()) //设置认证失败处理器
.accessDeniedHandler(new NotAccessHandler()); //设置无权访问处理器再次访问试试:

设置sys:test权限:
http.authorizeHttpRequests().antMatchers("/sys/test").hasAnyAuthority("sys:list", "sys:test");再次访问:

**hasAuthority()**:拥有某个权限才能访问;
//权限认证
http.authorizeHttpRequests().antMatchers("/sys/test").hasAuthority("sys:test");**hasRole()**:拥有某个角色才能访问;
我们在定义角色时一定要加ROLE_前缀:
USER_ROLE_DATABASE.put("xlw", ListUtil.of("ROLE_ADMIN"));我们在设置角色时候一定不要加ROLE_前缀,因为SpringSecurity会自动帮我们拼接上,因此ROLE_ADMIN设置hasRole()参数只要ADMIN即可,否则会报错:
//权限认证
http.authorizeHttpRequests().antMatchers("/sys/test").hasRole("ADMIN");**hasAnyRole()**:拥有任一角色即可访问;
http.authorizeHttpRequests().antMatchers("/sys/test").hasAnyRole("ADMIN", "SYSTEM");小妙招:
hasAnyAuthority可以即包含某权限或者角色>http.authorizeHttpRequests().antMatchers("/sys/test").hasAnyAuthority("sys:test", "ROLE_ADMIN");
7.2)注解式鉴权:
我们也可以通过注解的方式来进行鉴权,使用注解先要在启动类上加上:
@EnableGlobalMethodSecurity(securedEnabled=true, prePostEnabled=true)@Secured:
判断是否具有角色,另外需要注意的是这里匹配的字符串需要添加前缀
ROLE_。
@Secured({"ROLE_ADMIN"})
@GetMapping("test")
public Result<String> test() {
return Result.success("ok");
}@PreAuthorize:
权限检验,请求到来访问控制单元之前必须包含xx权限才能访问,控制单元方法执行前进行角色校验。
支持权限和角色的校验:
- hasRole(‘ROLE_NAME’):检查用户是否具有指定角色
- hasAnyRole(‘ROLE1’, ‘ROLE2’):检查用户是否具有给定角色中的任意一个。
- hasAuthority(‘AUTHORITY_NAME’):检查用户是否具有指定权限。
- hasAnyAuthority(‘AUTHORITY1’, ‘AUTHORITY2’):检查用户是否具有给定权限中的任意一个。
- hasPermission(targetObject, ‘permission’): 检查用户是否具有特定对象的特定权限。
//拥有角色
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("test")
public Result<String> test() {
return Result.success("ok");
}//拥有权限
@PreAuthorize("hasAuthority('sys:test')")
@GetMapping("test")
public Result<String> test() {
return Result.success("ok");
}@PostAuthorize:
权限检验,请求到来访问控制单元之后必须包含xx权限才能访问 ,控制单元方法执行完后进行角色校验。
@PostAuthorize("hasRole('ADMIN')")
@GetMapping("test")
public Result<String> test() {
return Result.success("ok");
}@PostFilter:
权限验证之后对数据进行过滤 留下用户名是
dingwen的数据。需要开启
@EnableGlobalMethodSecurity(prePostEnabled = true)
@GetMapping("/postFilter")
@ResponseBody
@PreAuthorize("hasAnyRole('ROLE_管理员')")
@PostFilter("filterObject.username == 'dingwen'")
public List<UserEntity> postFilterTest() {
List<UserEntity> userEntityList = new ArrayList<>();
userEntityList.add(UserEntity.builder().username("test").build());
userEntityList.add(UserEntity.builder().username("dingwen").build());
return userEntityList;
}@PreFilter:
进入控制器之前对数据进行过滤,可对入参进行过滤
需要开启
@EnableGlobalMethodSecurity(prePostEnabled = true)
@GetMapping("/preFilter")
@ResponseBody
@Secured({"ROLE_管理员"})
@PreFilter(value = "filterObject.username == 'dingwen'")
public void preFilterTest(List<UserEntity> userEntityList){
System.out.println();
}