【问题标题】:Spring Boot expression based access control property not found找不到基于 Spring Boot 表达式的访问控制属性
【发布时间】:2017-10-24 11:01:32
【问题描述】:

我正在使用 Spring-data-rest 公开一些实体,我想使用 Spring 表达式语言配置访问控制并进行预授权,以便用户只能操作属于他的实体。

我的主体对象在其用户名(字符串)中包含用户 ID,并且用户有一个属性 ID(长):

@Entity
@Table(name = "users")
@Getter
@Setter
public class User {

  @Id
  @Column(name = "user_id", nullable = false, updatable = false)
  private Long id;

  ...

}

我的存储库如下所示:

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

  @Override
  @PreAuthorize("hasRole('ROLE_ADMIN')")
  User findOne(Long id);

  @Override
  @PreAuthorize("#user.id == principal.username")
  void delete(User user);

  ...

}

但是,当以 id 1 的用户身份进行身份验证时调用 DELETE /users/1(主体在其用户名中包含此 id),我得到以下异常:

java.lang.IllegalArgumentException: Failed to evaluate expression '#user.id == principal.username'
...
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'id' cannot be found on null

我的表达基于官方Spring documentation。有人能指出我在这里缺少什么吗?

编辑: 我在我的存储库中添加了所有方法,因为它们似乎是相互关联的。

【问题讨论】:

    标签: java spring-boot spring-security spring-el


    【解决方案1】:

    在您的课程User 中,您必须注意idprivate,因此您的代码应该调用公共方法来获取用户ID,所以它必须是这样的:

      @Override
      @PreAuthorize("#user.getId() == authentication.getName()")
      void delete(@RequestParam(name="user", required=true)User user);
      .....
    

    您还必须调用公共方法才能从主体获取用户名。

    另外,请注意,您可以调用安全检查函数来执行更多逻辑,例如:

      @Autowired
      private SecurityCheck securityCheck;
    
      ................
    
      @Override
      @PreAuthorize("@securityCheck.check(#user,authentication)")
      void delete(User user);
    

    并且在 SecurityCheck 类中可以这样定义:

    @Component
    public class SecurityCheck {
    
    
    public boolean check(User user, Authentication authentication) {
        if(user == null)
            return false;
       if(user.getId().equals(authentication.getName()))    
           return true;
       // more logic ... 
       return false;
     }
    }
    

    【讨论】:

    • 谢谢,这行得通。但现在我无法访问主体:Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1004E: Method call: Method getUsername() cannot be found on java.lang.String type
    • 我还必须将用户设置为参数:void delete(@Param("user") User user);
    • 我认为你必须使用身份验证而不是主体
    • 很遗憾,它仍然认为认证对象是一个String:EL1004E: Method call: Method check(com.example.User,java.lang.String) cannot be found on com.example.SecurityCheck type
    • 你导入了 'org.springframework.security.core.Authentication' 吗?
    猜你喜欢
    • 2022-11-10
    • 2015-11-07
    • 1970-01-01
    • 2020-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-24
    • 1970-01-01
    相关资源
    最近更新 更多