春季会议:将会话ID生成逻辑从UUID更改为自说请求标头的自定义生成

时间:2019-01-26 12:48:58

标签: spring spring-boot spring-security spring-webflux spring-session

我正在使用Spring Webflux,并且在实现ReactiveAuthenticationManager之后,下一个任务是将会话保留在Redis中。

我不是从UUID随机创建会话ID(redis键),而是要从请求标头中选择用户名标头,并将其设置为要保留在redis中的sessionId。

原因:我的客户已经通过第三方服务进行了身份验证,我只想从redis中检查其授予的权限(而不是每次都从数据库中检查)。请求中没有包含sessionId的cookie,而且我希望将会话映射到userName标头,而不是spring生成的会话ID(随机UUID)。

我尝试过的事情:

我尝试通过在 Webfilter ServerSecurityContextRepository 加载中获取 ServerWebExchange 来更改 Websession 方法,但是这里的 ServerWebExchange 不允许我将sessionId更改为固定值(或某些生成逻辑)

代码段:

@Component
public class SecurityContextRepository implements ServerSecurityContextRepository {

    private final DaoAuthenticationManager authenticationManager;

    @Autowired
    public SecurityContextRepository(DaoAuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @Override
    public Mono<Void> save(ServerWebExchange swe, SecurityContext sc) {
    throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public Mono<SecurityContext> load(ServerWebExchange swe) {
    ServerHttpRequest request = swe.getRequest();
        if (request.getHeaders().containsKey("userName") &&
        !Objects.requireNonNull(request.getHeaders().get("userName")).isEmpty()) {
            String userName = Objects.requireNonNull(swe
            .getRequest()
            .getHeaders()
            .get("userName")).get(0);

            Authentication auth = new UsernamePasswordAuthenticationToken(userName,
            Security.PASSWORD);
            return this.authenticationManager.authenticate(auth).map(SecurityContextImpl::new);
        } else {
            return Mono.empty();
        }
    }
}

@Component
public class DaoAuthenticationManager implements ReactiveAuthenticationManager {

    private final DaoUserDetailsService userDetailsService;

    private final Scheduler scheduler;

    @Autowired
    public DaoAuthenticationManager(DaoUserDetailsService userDetailsService,
    Scheduler scheduler) {
        Assert.notNull(userDetailsService, "userDetailsService cannot be null");
        this.userDetailsService = userDetailsService;
        this.scheduler = scheduler;
    }

    @Override
    public Mono<Authentication> authenticate(Authentication authentication) {
        final String username = authentication.getName();
        return this.userDetailsService.findByUsername(username)
            .publishOn(this.scheduler)
            .switchIfEmpty(
                Mono.defer(() -> Mono.error(new 
UsernameNotFoundException("Invalid Username"))))
            .map(u -> new UsernamePasswordAuthenticationToken(u, u.getPassword(),
            u.getAuthorities()));
    }
}

@Configuration
@EnableRedisWebSession(redisNamespace = Constants.DEFAULT_SESSION_NAMESPACE, maxInactiveIntervalInSeconds = Constants.SESSION_LIFECYCLE)
public class RedisConfig {

}

UserDetailsS​​ervice基于UserRepository,后者从关系表中获取用户的角色。

  • 有关如何对sessionExchange进行突变以将sessionId设置为userId的任何指针
  • 我希望修改加载方法,以便首先从会话中获取角色,并验证从JDBC进行的其他检查,然后重新放入redis。

也欢迎其他最佳做法或解决方法。

0 个答案:

没有答案