Spring Security:全局方法安全性不起作用

Posted

技术标签:

【中文标题】Spring Security:全局方法安全性不起作用【英文标题】:Spring Security: global method security not working 【发布时间】:2021-12-15 21:54:36 【问题描述】:

我已经配置了 Keycloack 并且我的身份验证服务器工作正常,但是由于 Spring 不推荐使用以前的 OAuth2 支持,我不确定我的配置是否准确。它是一个简单的学习应用程序,我正在尝试在方法级别添加预授权,以便当前经过身份验证的用户可以添加他们的锻炼数据并自己查看它们。它还将删除端点仅限于管理员用户 (fitnessadmin) 但我对配置感到困惑。

我的控制器类

@RestController
@RequestMapping("/workout")
public class WorkoutController 

    @Autowired
    private WorkoutService workoutService;

    @PostMapping("/")
    public void add(@RequestBody Workout workout) 
        workoutService.saveWorkout(workout);
    

    @GetMapping("/")
    public List<Workout> findAll() 
        return workoutService.findWorkouts();
    

    @DeleteMapping("/id")
    public void delete(@PathVariable Integer id) 
        workoutService.deleteWorkout(id);
    

存储库类

public interface WorkoutRepository extends JpaRepository<Workout, Integer> 

    @Query("SELECT w FROM Workout w WHERE w.user = ?#authentication.name")
    List<Workout> findAllByUser();

服务等级

@Service
public class WorkoutService 
    
    @Autowired
    private WorkoutRepository repository;
    
    @PreAuthorize("#workout.user == authentication.name")
    public void saveWorkout(Workout workout) 
        repository.save(workout);
    
    
    public List<Workout> findWorkouts() 
        return repository.findAllByUser();
    
    
    public void deleteWorkout(Integer id) 
        repository.deleteById(id);
    
    

配置类

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends WebSecurityConfigurerAdapter
    
    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http
          .authorizeRequests(authz -> authz
            .mvcMatchers(HttpMethod.DELETE, "/**").hasAuthority("fitnessadmin")
            .anyRequest().authenticated())
          .oauth2ResourceServer(oauth2 -> oauth2.jwt());
    
    @Bean
    public SecurityEvaluationContextExtension 
                       securityEvaluationContextExtension() 
       return new SecurityEvaluationContextExtension();
    

应用程序.yaml

server: 
  port: 8086

spring:
  datasource:  
    url: jdbc:mysql://localhost:3306/db2?useSSL=false 
    username: username  
    password: password
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: http://localhost:8080/auth/realms/master
          
claim:
  aud: fitnessapp

我有 3 个用户,分别是 mary、bill、rachel,只有 mary 是“fitnessadmin”并且可以删除。其余用户是“fitnessuser”

这是解码后的令牌:


  "exp" : 1635741988,
  "nbf" : null,
  "iat" : 1635734788,
  "auth_time" : null,
  "jti" : "9b319b1b-7687-4842-b211-02e3d1aaec3c",
  "iss" : "http://localhost:8080/auth/realms/master",
  "aud" : "fitnessapp",
  "sub" : "8fe23dba-d692-4933-9bca-c5f69ff3d408",
  "typ" : "Bearer",
  "azp" : "fitnessapp",
  "nonce" : null,
  "session_state" : "c471f77f-8efa-449b-982d-90ea942f329e",
  "at_hash" : null,
  "c_hash" : null,
  "name" : null,
  "given_name" : null,
  "family_name" : null,
  "middle_name" : null,
  "nickname" : null,
  "preferred_username" : null,
  "profile" : null,
  "picture" : null,
  "website" : null,
  "email" : null,
  "email_verified" : null,
  "gender" : null,
  "birthdate" : null,
  "zoneinfo" : null,
  "locale" : null,
  "phone_number" : null,
  "phone_number_verified" : null,
  "address" : null,
  "updated_at" : null,
  "claims_locales" : null,
  "acr" : "1",
  "s_hash" : null,
  "trusted-certs" : null,
  "allowed-origins" : null,
  "realm_access" : null,
  "resource_access" : null,
  "authorization" : null,
  "cnf" : null,
  "scope" : "fitnessapp",
  "sid" : "c471f77f-8efa-449b-982d-90ea942f329e",
  "user_name" : "bill",
  "authorities" : [ "fitnessuser" ]

正如我提到的,我的困惑在于配置类。此实现在不同端点上给出以下错误:

findAll():

org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'authentication' cannot be found on object of type 'java.lang.Object[]' - maybe not public or not valid?

添加():

403 Forbidden

非常感谢您的帮助。提前致谢!

更新 我想我错过了评论中建议的 SecurityEvaluationContextExtension 并且我已经更新了代码,但我仍然遇到同样的错误。

【问题讨论】:

您注册SecurityEvaluationContextExtension 为使用 Spring Data + Spring Security 的 bean 了吗? 这很重要,我错过了,但我仍然收到未经授权的错误 太奇怪了!所以我想让你在这里确认的一件事是,在你打电话给repository.findAllByUser() 之前尝试打电话给Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); String name = authentication.getName();,看看name 是否存在。 【参考方案1】:

我猜你需要修复的错误是查询中的身份验证对象。

public interface WorkoutRepository extends JpaRepository<Workout, Integer> 

    @Query("SELECT w FROM Workout w WHERE w.user = ?#authentication.name")
    List<Workout> findAllByUser();

Authentication 不是您可以通过这种方式访问​​的对象,但如果您想访问 spring bean,您可以创建 Authentication.java 并在该类中创建 name 字段。

最好的办法是

public interface WorkoutRepository extends JpaRepository<Workout, Integer> 
    
    @Query("SELECT w FROM Workout w WHERE w.user =:name")
    List<Workout> findAllByUser(@Param("name") String name);

【讨论】:

以上是关于Spring Security:全局方法安全性不起作用的主要内容,如果未能解决你的问题,请参考以下文章

将 Spring Security 全局方法安全性与 Keycloak 集成

使用 Spring Security 3.2.4 for Jersey 2.9 REST 服务的全局方法安全性的正确配置是啥?

将 AccessDeniedException 传播到 Spring Security 3.2

PermitAll 在 Spring Security 中不起作用

Spring Security 会话管理会话固定保护不起作用

spring boot starter 安全发布方法不起作用