java - Spring 数据休息: How to publish a user management api

标签 java spring spring-security spring-data spring-data-rest

是否可以公开 Spring Data Rest 生成的 API 来管理使用 Spring Security 进行身份验证和访问控制的相同用户?

考虑实体:

@Entity
public class User implements UserDetails {
   ....
}

与 Spring Security 一起使用:

@Service
public class RepositoryUserDetailsService implements UserDetailsService{

    private final UnsecuredUserRepository users;

    @Autowired
    public RepositoryUserDetailsService(UnsecuredUserRepository users) {
        this.users = users;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User one = users.findOne(username);
        if (one == null) {
            throw new UsernameNotFoundException("No such user");
        }
        return one;
    }

}

它使用以下 spring 数据存储库:

public interface UnsecuredUserRepository extends CrudRepository<User, String> {
}

我现在想要添加一个管理 API 来管理用户。 Spring data Rest 可以为我做到这一点,并且我可以使用 spring security 来保护它。

@PreAuthorize("hasRole('ROLE_USER_MANAGER')")
public interface UserRepository extends CrudRepository<User, String>, UserSignUpExtension {

    @Override
    @PreAuthorize("hasRole('ROLE_USER_MANAGER') or #userName == authentication?.name")
    void delete(@Param("userName") String userName);

}

问题是一个人不能拥有 multiple repositories for the same entities with spring data rest ,使用安全的存储库会产生先有鸡还是先有蛋的问题,并阻止我使用创建默认用户的启动代码(因为安全检查已经强制执行)。

最佳答案

我最终通过拥抱 Spring 安全性而不是试图规避它来解决这个问题。

我实现了这个实用程序:

import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;

public class AsInternalUser implements AutoCloseable {

    private final SecurityContext previousContext;

    public AsInternalUser() {
        previousContext = SecurityContextHolder.getContext();
        SecurityContext context = SecurityContextHolder.createEmptyContext();
        context.setAuthentication(
                new AnonymousAuthenticationToken("INTERNAL","INTERNAL_USERNAME", AuthorityUtils.createAuthorityList("ROLE_INTERNAL"))
        );
        SecurityContextHolder.setContext(
                context
        );
    }

    @Override
    public void close() {
        if (previousContext == null) {
            SecurityContextHolder.clearContext();
        } else {
            SecurityContextHolder.setContext(previousContext);
        }
    }
}

我的初始用户创建因此变为:

try (AsInternalUser __ = new AsInternalUser()) {
            if (!users.exists(DEFAULT_ADMIN_NAME)) {
                users.save(new User(DEFAULT_ADMIN_NAME, passwordEncoder.encode(DEFAULT_ADMIN_PASSWORD), Arrays.asList(Roles.values())));
            }
        }

当然,存储库需要授予对新 ROLE_INTERNAL 的访问权限

@PreAuthorize("hasAnyRole('ROLE_USER_MANAGER', 'ROLE_INTERNAL')")
public interface UserRepository extends CrudRepository<User, String>, UserSignUpExtension {
}

用户注册等其他地方也必须升级为内部角色。

我认为这是比规避安全模型更好的方法,因为它允许更精细的控制,并减少意外调用不安全的存储库和损害安全性的机会。

关于java - Spring 数据休息: How to publish a user management api,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40367131/

相关文章:

java - 使用 spring SecurityWebFilterChain 如何禁用/阻止除少数已知路径之外的所有非 https 请求

java - 如何在 Hibernate 中正确设置 UTF-8?

java - Jdbc Odbc 错误。我无法连接到 ODBC 驱动程序

java - 在设置属性之前,bean 被注入(inject)到构造函数 arg 中

java - Spring Integration 从 REST 服务获取分页结果

mysql - Spring Boot、Spring Security、MySQL - CustomUserDetailsS​​ervice 始终导致错误 "Invalid Username or Password"

java - FirstGroup 类型的 onBackPressed() 方法必须重写父类(super class)方法

java - 从数组调用方法

java - Spring Boot RabbitMQ 接收器 Jackson 反序列化为 POJO

java - 如何为 token 设置资源 ID?