【SpringBoot3】Spring Security 常用注解

注:本文基于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 常见扩展点

Spring Security 提供了许多扩展点,允许开发者根据具体需求进行定制和扩展。以下是一些常见的扩展点:

  1. 过滤器链(Filter Chain)
    Spring Security 本质是一个过滤器链,开发者可以通过自定义过滤器来扩展其功能。例如,可以添加自定义的认证过滤器、授权过滤器或会话管理过滤器等。

  2. 认证机制(Authentication Mechanism)
    可以自定义认证机制,包括用户信息的加载、密码的编码和校验等。通过实现 AuthenticationProvider 接口,可以定义自己的认证逻辑。

  3. 授权决策(Authorization Decision)
    开发者可以通过实现 AccessDecisionManager 接口来自定义授权决策逻辑。这允许你根据业务逻辑来定制权限判断。

  4. 用户服务(User Service)
    通过实现 UserDetailsService 接口,可以自定义用户信息的加载方式。例如,你可以从数据库、LDAP 服务器或其他数据源中获取用户信息。

  5. 安全事件监听(Security Event Listeners)
    Spring Security 提供了安全事件监听器,允许你监听认证、授权等事件,并根据事件执行相应的操作。

  6. 方法安全(Method Security)
    除了使用注解外,你还可以通过配置 GlobalMethodSecurityConfiguration 来全局启用方法级别的安全支持,并自定义方法安全的配置。

  7. 安全表达式语言(Security Expression Language)
    Spring Security 使用了强大的安全表达式语言(SpEL),允许你在注解和配置中使用表达式来定义复杂的权限和角色要求。

  8. 会话管理(Session Management)
    可以自定义会话的创建、存储、失效等逻辑,以满足特定的业务需求。

  9. HTTP 安全配置(HTTP Security Configuration)
    通过重写 configure(HttpSecurity http) 方法,你可以自定义 HTTP 安全配置,包括 CSRF 保护、点击劫持保护、缓存控制等。

  10. 异常处理(Exception Handling)
    可以自定义认证和授权失败时的异常处理逻辑,例如返回自定义的错误页面或错误信息。

这些扩展点使得 Spring Security 非常灵活,能够适应各种不同的安全需求。通过合理利用这些扩展点,开发者可以构建出强大而安全的应用程序。

参考

  • 20
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

顽石九变

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值