赞
踩
注:本文基于
Spring Boot 3.2.1
以及Spring Security 6.2.1
Spring Security 6 的常用注解包括以下几种,通过这些注解可以更加方便的控制资源权限。
@Secured
:方法执行前检查,直接判断有没有对应的角色@PreAuthorize
:方法执行前检查,根据SpEL表达式执行结果判断是否授权@PostAuthorize
:方法执行后检查,根据SpEL表达式执行结果判断是否授权要使用以前注解必须增加配置,开启校验功能
// 用于启用方法级别的安全支持
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
@Secured
方法执行前检查,直接判断有没有对应的角色
示例代码:
@Secured({ "ROLE_USER" })
public void create(Contact contact);
@Secured({ "ROLE_USER", "ROLE_ADMIN" })
public void update(Contact contact);
@Secured({ "ROLE_ADMIN" })
public void delete(Contact contact);
@PreAuthorize
方法执行前检查,根据SpEL表达式执行结果判断是否授权
示例代码:
// 有角色
@PreAuthorize("hasRole('ROLE_ADMIN')")
// 有任一角色
@PreAuthorize("hasAnyRole({'ROLE_USER','ROLE_ADMIN'})")
// 有任一权限
@PreAuthorize("hasAnyAuthority({'user:search','user:edit'})")
其他用法
@PreAuthorize
参数是SpEL表达式,所以还可以有其他用法
1、方法参数值判断,@PreAuthorize("#age>10")
@GetMapping("/age")
@PreAuthorize("#age>10")
public String age(Integer age) {
return "Hello age "+ age;
}
2、调用bean的方法判断
1)创建Bean,判断是否有权限
@Component("au")
public class AuthUtils {
public boolean check(String role) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.noneMatch(role::equals)) {
throw new AccessDeniedException("User does not have the required permission");
}
return true;
}
}
2)在方法上使用,@PreAuthorize("@au.check('ROLE_USER')")
@GetMapping("/user_au")
@PreAuthorize("@au.check('ROLE_USER')")
public String user_au() {
return "Hello user_au";
}
和@PreAuthorize
配合使用的方法定义在 org.springframework.security.access.expression.SecurityExpressionOperations
中
1、HttpSecurity 配置
@EnableWebSecurity @Configuration @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) public class BasicSecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests((authorize) -> authorize // 放行登录页面 .requestMatchers("/login").permitAll() // 拦截其他所有请求 .anyRequest().authenticated() ) // 退出时,让session失效 .logout(logout -> logout.invalidateHttpSession(true)) // 配置登录页面 和 登录成功后页面 .formLogin(form -> form.loginPage("/login").permitAll() .loginProcessingUrl("/login").defaultSuccessUrl("/index")); http.exceptionHandling(e->e.accessDeniedPage("/noAuth")); // 开启csrf 保护 http.csrf(Customizer.withDefaults()); return http.build(); } @Bean public UserDetailsService userDetailsService() { UserDetails user1 = User.withUsername("admin").password("{noop}123456").roles("ADMIN").build(); UserDetails user2 = User.withUsername("user").password("{noop}123456").authorities("user:edit","ROLE_USER").build(); return new InMemoryUserDetailsManager(user1,user2); } @Bean public PasswordEncoder passwordEncoder() { return PasswordEncoderFactories.createDelegatingPasswordEncoder(); } }
2、测试controller类,DemoController
import org.springframework.security.access.annotation.Secured; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class DemoController { @GetMapping("/admin") @Secured({"ROLE_ADMIN"}) public String admin() { return "Hello admin"; } @GetMapping("/user") @Secured({"ROLE_ADMIN","ROLE_USER"}) public String user() { return "Hello user"; } @GetMapping("/admin2") @PreAuthorize("hasRole('ROLE_ADMIN')") public String admin2() { return "Hello admin"; } @GetMapping("/user2") @PreAuthorize("hasAnyRole({'ROLE_USER','ROLE_ADMIN'})") public String user2() { return "Hello user"; } @GetMapping("/user_perm") @PreAuthorize("hasAnyAuthority({'user:search','user:edit'})") public String user_perm() { return "Hello user"; } @GetMapping("/user_au") @PreAuthorize("@au.check('ROLE_USER')") public String user_au() { return "Hello user_au"; } @GetMapping("/age") @PreAuthorize("#age>10") public String age(Integer age) { return "Hello age "+ age; } @RequestMapping("/all") public String all() { return "Hello all"; } }
如果需要自定义认证和授权逻辑,可以实现 UserDetailsService 和 AuthenticationProvider 接口,并在配置类中注入这些自定义的 Bean。
这就是 Spring Security 的注解验证流程。通过合理地使用注解和配置类,可以轻松地实现基于角色的访问控制、方法级别的授权等安全功能。同时,Spring Security 还提供了丰富的扩展点,允许开发者根据具体需求进行定制。
Spring Security 提供了许多扩展点,允许开发者根据具体需求进行定制和扩展。以下是一些常见的扩展点:
过滤器链(Filter Chain):
Spring Security 本质是一个过滤器链,开发者可以通过自定义过滤器来扩展其功能。例如,可以添加自定义的认证过滤器、授权过滤器或会话管理过滤器等。
认证机制(Authentication Mechanism):
可以自定义认证机制,包括用户信息的加载、密码的编码和校验等。通过实现 AuthenticationProvider
接口,可以定义自己的认证逻辑。
授权决策(Authorization Decision):
开发者可以通过实现 AccessDecisionManager
接口来自定义授权决策逻辑。这允许你根据业务逻辑来定制权限判断。
用户服务(User Service):
通过实现 UserDetailsService
接口,可以自定义用户信息的加载方式。例如,你可以从数据库、LDAP 服务器或其他数据源中获取用户信息。
安全事件监听(Security Event Listeners):
Spring Security 提供了安全事件监听器,允许你监听认证、授权等事件,并根据事件执行相应的操作。
方法安全(Method Security):
除了使用注解外,你还可以通过配置 GlobalMethodSecurityConfiguration
来全局启用方法级别的安全支持,并自定义方法安全的配置。
安全表达式语言(Security Expression Language):
Spring Security 使用了强大的安全表达式语言(SpEL),允许你在注解和配置中使用表达式来定义复杂的权限和角色要求。
会话管理(Session Management):
可以自定义会话的创建、存储、失效等逻辑,以满足特定的业务需求。
HTTP 安全配置(HTTP Security Configuration):
通过重写 configure(HttpSecurity http)
方法,你可以自定义 HTTP 安全配置,包括 CSRF 保护、点击劫持保护、缓存控制等。
异常处理(Exception Handling):
可以自定义认证和授权失败时的异常处理逻辑,例如返回自定义的错误页面或错误信息。
这些扩展点使得 Spring Security 非常灵活,能够适应各种不同的安全需求。通过合理利用这些扩展点,开发者可以构建出强大而安全的应用程序。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。