Spring boot 我是否可以基于来自控制器方法的一些信息,使用Spring security为端点实现授权/筛选?

Spring boot 我是否可以基于来自控制器方法的一些信息,使用Spring security为端点实现授权/筛选?,spring-boot,spring-security,Spring Boot,Spring Security,我有一个控制器方法,看起来像这样 @GetMapping public ResponseEntity<String> getInformation(@PathVariable("id") String id, InternalAuthInfo info) { // do something return new ResponseEntity(value, HttpStatus.OK); } @GetMapping 公共响应属性getInformation(@PathVari

我有一个控制器方法,看起来像这样

@GetMapping
public ResponseEntity<String> getInformation(@PathVariable("id") String id, InternalAuthInfo info) {
  // do something
  return new ResponseEntity(value, HttpStatus.OK);
}
@GetMapping
公共响应属性getInformation(@PathVariable(“id”)字符串id,InternalAuthInfo信息){
//做点什么
返回新的ResponseEntity(值,HttpStatus.OK);
}
我想做的是根据InternalAuthInfo信息对象的信息过滤/授权一些get调用,我不想在控制器内部实现过滤逻辑


我是否可以使用spring security实现此功能?

您可以为api用户分配一个角色,然后在控制器中使用@PreAuthorize注释

@GetMapping
@PreAuthorize("hasRole(ALLOWED_ROLE')")
public ResponseEntity<String> getInformation(@PathVariable("id") String id, InternalAuthInfo info) {
  // do something
  return new ResponseEntity(value, HttpStatus.OK);
}
@GetMapping
@预授权(“hasRole(允许的角色”))
公共响应属性getInformation(@PathVariable(“id”)字符串id,InternalAuthInfo信息){
//做点什么
返回新的ResponseEntity(值,HttpStatus.OK);
}

参考资料:

这实际上取决于您想要的复杂程度,但让我们简单地开始

在SpringSecurity中,有用于检索用户和用户权限的服务API。例如
UserDetailsService
。一般来说,如果您试图从数据库中获取用户,例如基于用户名,那么这是一个很好的选择。这也是Spring Security默认选择用于用户名/密码身份验证的API

因此,您可以创建一个委托
UserDetailsService
,如下所示:

public class InternalAuthInfoUserDetailsService implements UserDetailsService {
    UserDetailsService delegate = new JdbcUserDetailsManager();

    public UserDetails loadUserByUsername(String username) {
        User user = this.delegate.loadUserByUsername(username);
        InternalAuthInfo info = myWayToLookThisUp(username);
        Collection<GrantedAuthority> roles = myWayToMapInfo(info);
        return new User(user.getUsername(), user.getPassword(), roles);
    }
}
这种方法的思想是将详细信息从
InternalAuthInfo
映射到您将决定的各种授权角色,如
ROLE\u USER
。此时,有两种受支持的过滤方法:

@PreAuthorize("hasRole('USER')")
@GetMapping(...
正如另一张海报所说,这是一个非常简单的方法

或者,如果要将
InternalAuthInfo
实例作为用户主体的一部分进行维护,则可以在自定义
UserDetailsService
中创建桥接对象:

@Bean
UserDetailsService userDetailsService() {
    return new InternalAuthInfoUserDetailsService();
}
public class InternalAuthInfoUserDetailsService 
    implements UserDetailsService {

    UserDetailsService delegate = new JdbcUserDetailsManager();

    public UserDetails loadUserByUsername(String username) {
        User user = this.delegate.loadUserByUsername(username);
        InternalAuthInfo info = myWayToLookThisUp(username);
        return new MyUser(info, user);
    }

    private static class MyUser extends InternalAuthInfo
        implements UserDetails {

        private final UserDetails delegate;

        public MyUser(InternalAuthInfo info, UserDetails user) {
            super(info);
            this.delegate = user;
        }

        // ... delegate methods
    }
}
其余的接线是一样的,但用法有点不同

通过此设置,您可以直接在授权表达式中引用
InternalAuthInfo

@PreAuthorize("principal?.someAuthInfoProperty == 'some-value'")
@GetMapping(...
其中,我假设
InternalAuthInfo
具有类似于
getSomeAuthInfoProperty
的方法

顺便说一句,
UserDetailsService
通常假定一组特定的数据库表和列。因此,您可能会有一个利用Spring Data JPA之类的实现:

public class InternalAuthInfoUserDetailsService
    implements UserDetailsService {

    @Autowired
    private InternalAuthInfoRepository repository;

    @Override
    public User loadUserByUsername(String username) {
        InternalAuthInfo info = this.repository.findByUsername(username);
        return new MyInternalAuthInfoUser(info);
    }
}
但是,这里我们开始对您的设置进行其他假设

这里的要点是你可以

  • 实施
    userdetails服务
    ,将
    InternalAuthInfo
    转换为一组
    GrantedAuthority
    s-这些将成为
    身份验证#getAuthority
  • 这里的优点是简化了表示,仅在身份验证语句中引用SpringSecurity公民

  • 实现一个
    UserDetailsService
    ,将Spring Security的
    User
    域对象和
    InternalAuthInfo
    对象连接起来-这些将成为
    Authentication\getPrincipal
  • 这里的优点是,身份验证语句既包含Spring Security citizens,也包含
    InternalAuthInfo
    的一个实例,用于更复杂的检查


    最后,这不完全是您的问题,但我想指出,用户可以在方法级授权和过滤器级授权之间进行选择。它们各有优缺点,但我建议大家看一下,因为你可以用表达式来描述整个应用程序的规则,而不是逐个方法。我在这里一个接一个地使用这个方法只是为了便于演示。

    谢谢您的回答@fctmolina。但是如何将信息从InternalAuthInfo传递到我的过滤器类?这就是我正在努力解决的问题。