Кэш пользовательских данных приложений с Spring Security

В нашем микросервисе каждый пользователь Spring Security, прошедший проверку подлинности, имеет связанную с приложением структуру данных.
думая о том, как мы можем легко кэшировать эти данные вместе с пользователем, мы подумали, что было бы хорошо, если бы это можно было сделать похожим на это:

  1. добавление кэшированных данных в проверку подлинности в памяти при создании пользователей:

    public void configureGlobal(AuthenticationManagerBuilder auth) {
        auth.inMemoryAuthentication().withUser("user").password("123").roles("ROLE");
        auth.inMemoryAuthentication().withUser("user").cache(appDate);
        ...
    }
    
  2. извлеките данные в методах @RestController:

    @RequestMapping("/foo")
    public void foo() {    
        User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Object details = SecurityContextHolder.getContext().getAuthentication().getDetails();    
        Object cachedAppDate= SecurityContextHolder.getContext().getAuthentication().getCachedData();    
    }
    

Очевидно, что метод, выделенный жирным шрифтом, является списком желаний и не существует.
Есть советы, как сделать это легко с помощью существующей платформы безопасности Spring?

Спасибо!

1 ответ

  1. Если вы можете получить кэшированные данные, используя только имя пользователя (пароль не требуется), вы можете использовать реализацию org.springframework.security.core.userdetails.UserDetailsService, она имеет только один метод —UserDetails loadUserByUsername(String username), и возвращать необходимые данные в качестве пользовательского объекта UserDetail. После реализации интерфейса просто передайте его как UserDetailService для AuthenticationManagerBuilder.

    Если вам нужен пароль, чтобы получить эти кэшированные данные, все стало немного сложнее.
    Вы должны создать свой собственный AuthenticationProvider и поместить кэшированные данные в Principal или UserDetails. Например код для набора дополнительных данных в Principal:

    public class MyProvider implements org.springframework.security.authentication.AuthenticationProvider {
    
        @Override
        public boolean supports(Class<? extends Object> authentication) {
            return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
        }
    
        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;
    
            ... // check login/password
    
            Object cachedAppDate = "i'm cached data!";
            MyUser user = new MyUser(token, cachedData); 
            UsernamePasswordAuthenticationToken output = new UsernamePasswordAuthenticationToken(user, authentication.getCredentials(), user.getAuthorities());
            output.setDetails(authentication.getDetails());
            return output;
        }
    
    }
    
    public static class MyUser extends org.springframework.security.core.userdetails.User {
    
            private final Object cachedData;
    
            public User(UsernamePasswordAuthenticationToken token, Object cachedData) {
                super(token.getName(), "", token.getAuthorities());
                this.cachedData = cachedData;
            }
    
            public Object getCachedData() {
                return this.cachedData;
            }
        }
    

    и доступ к кэшированным данным как ((MyUser)SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getCachedData();