Не удалось получить зарегистрированного пользователя из ReactiveSecurityContextHolder в Spring Aspect - PullRequest
0 голосов
/ 27 марта 2019

Я хочу написать простой аспект для включения фильтрации Hibernate на некоторых сервисах.Мне это нужно для реализации некоторых «правил видимости».Но я не знаю, как это сделать с WebFlux.ReactiveSecurityContextHolder.getContext() ничего не возвращает, когда я называю это в @Around аспекте.Я отладил код и обнаружил, что аутентификация начинается до выполнения Aspect и заканчивается после завершения Aspect.Кто-нибудь знает решение этой проблемы?Как я могу получить вход в систему пользователя от аспекта при использовании webflux?Мой аспект:

@Pointcut("execution(* com.shs.crm.dao.service.user.*.*(..))")
public void dataAccessOperation() {
    logger.info("dataAccessOperation performed");
}
@Around("com.shs.aspect.DataSecurityAspect.dataAccessOperation()")
public Object doAccessCheck(ProceedingJoinPoint proceedingJoinPoint)
        throws Throwable {
    Object returnObject;
    if (proceedingJoinPoint.getTarget() instanceof CrmUserService) {
        try {
           Long userId = customSecurityService.getCurrentUserId().toFuture().get();//here i have IllegalStateException
        } catch (Exception noContext) {
            logger.debug(
                    "No Security Context associated with current thread - assuming least access");
        }
        // Here i will enable filter
        returnObject = proceedingJoinPoint.proceed();
    } else {
        // here i will disable filter
        returnObject = proceedingJoinPoint.proceed();
    }
    return returnObject;
}

Сервис для получения текущего пользователя:

    @Service
public class CustomSecurityService {
    public Mono<Long> getCurrentUserId() {
        return ReactiveSecurityContextHolder.getContext().switchIfEmpty(Mono.error(new IllegalStateException("ReactiveSecurityContext is empty")))
                .map(SecurityContext::getAuthentication)
                .map(Authentication::getName)
                .map(Long::parseLong);
    }
}

Безопасность:

@Component
public class SecurityContextRepository implements ServerSecurityContextRepository{

    @Autowired
    private 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();
        String authHeader = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);

        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String authToken = authHeader.substring(7);
            Authentication auth = new UsernamePasswordAuthenticationToken(authToken, authToken);
            return this.authenticationManager.authenticate(auth).map((authentication) -> {
                return new SecurityContextImpl(authentication);
            });
        } else {
            return Mono.empty();
        }
    }

}

@Component
public class AuthenticationManager implements ReactiveAuthenticationManager {

    @Autowired
    private JWTUtil jwtUtil;

    @Autowired
    private CrmUserService userService;

    @Override
    public Mono<Authentication> authenticate(Authentication authentication) {
        String authToken = authentication.getCredentials().toString();

        Long userId;
        try {
            userId = jwtUtil.getUserIdFromToken(authToken);
        } catch (Exception e) {
            userId = null;
        }
        if (userId != null && jwtUtil.validateToken(authToken)) {

            Map<String, Claim> claims = jwtUtil.getAllClaimsFromToken(authToken);
            Set<Long> permissions = userService.getUserPermissionsIds(userId);
            //List<Long> permissions = claims.get("permissions").asList(Long.class);
            UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
                    userId,
                null,
                    permissions.stream().map( permission -> new SimpleGrantedAuthority(permission.toString())).collect(Collectors.toList())
            );
            return Mono.just(auth);
        } else {
            return Mono.empty();
        }
    }

    List<String> getPermissionsNamesByIds(List<Long> ids){
        return ids.stream().map(id -> {
            CrmPermission.AvailablePermissions permission = (CrmPermission.AvailablePermissions)CrmPermission.AvailablePermissions.fromValue(id.intValue());
            return permission.getCode();
        }).collect(Collectors.toList());
    }

}

Я могу получить текущего пользователя только с контроллера:

@RequestMapping(method = RequestMethod.GET)
    public Mono<CrmUserDto> getAccount(Principal principal) {
        return customSecurityService.getCurrentUserId().flatMap(userId -> {
            CrmUser currentUser = userRepository.findOneByIdWithRoles(userId);
            CrmUserDto userDTO = modelMapperService.map(currentUser, CrmUserDto.class);
            return Mono.just(userDTO);
        });
    }
...