Spring Boot несколько методов аутентификации - PullRequest
0 голосов
/ 24 марта 2019

Я использую Spring Boot 2.0.3. Я хочу использовать несколько методов аутентификации и настройки сервера ресурсов.

В настоящее время у меня есть:

  • один микросервис аутентификации / авторизации, который по сути является хранилищем токенов (и имеет доступ к базе данных реальных пользователей)
  • один сервер ресурсов, настроенный для проверки JWT в хранилище токенов

(см. Конфигурационные файлы ниже)

Все хорошо работает с JWT, но теперь я хочу предоставить пользовательские методы аутентификации, которые используют заголовки (один похож (но не) на базовую аутентификацию, а другой - с ключом / секретом API).

Мои исследования привели меня к определенным выводам, но, поскольку я довольно плохо знаком с безопасностью Spring, мне все еще неясно, какая глобальная архитектура, особенно с сервером авторизации.

Для меня будет иметь смысл, что любой запрос, поступающий на мой сервер ресурсов, будет проверяться на сервере авторизации, который будет возвращать авторизацию (аутентификацию и авторизацию).

Это будет означать, что мой сервер ресурсов должен отправить некоторые заголовки серверу авторизации и получить обратно авторизацию в случае, если JWT не предоставлен, так что автоматические проверки безопасности Spring выполнены правильно (роль и т. Д.), И я также вернусь ссылка пользователя как-то. И это должно быть сделано с надлежащей весенней модой, сохраняя при этом аутентификацию JWT.

Я видел:

Мои вопросы:

Какой весенний способ добиться этого?

файлы конфигурации

Аутентификационный сервер
@Configuration
@EnableAuthorizationServer
public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {

    private static final Logger log = Logger.getLogger(OAuth2Configuration.class.getName());

    @Value("${check-user-scopes}")
    private Boolean checkUserScopes;

    @Autowired
    private DataSource dataSource;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new LegacyPasswordEncoder();
    }

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Autowired
    private ClientDetailsService clientDetailsService;

    @Qualifier("authenticationManagerBean")
    @Autowired
    protected AuthenticationManager authenticationManager;

    @Bean
    public OAuth2RequestFactory requestFactory() {
        CustomOauth2RequestFactory requestFactory = new CustomOauth2RequestFactory(clientDetailsService);
        requestFactory.setCheckUserScopes(true);
        return requestFactory;
    }

    @Bean
    public TokenStore tokenStore() {
        return new MyTokenStore(dataSource);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource).passwordEncoder(passwordEncoder());
    }

    @Bean
    public TokenEndpointAuthenticationFilter tokenEndpointAuthenticationFilter() {
        return new TokenEndpointAuthenticationFilter(authenticationManager, requestFactory());
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
        oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints.tokenServices(tokenServices()).authenticationManager(authenticationManager).userDetailsService(userDetailsService);

        endpoints.exceptionTranslator(exception -> {
            if (exception instanceof OAuth2Exception) {
                OAuth2Exception oAuth2Exception = (OAuth2Exception) exception;
                return ResponseEntity
                        .status(oAuth2Exception.getHttpErrorCode())
                        .body(new CustomOauthException(oAuth2Exception.getMessage()));
            } else {
                throw exception;
            }
        });
        if (checkUserScopes)
            endpoints.requestFactory(requestFactory());
    }


    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices tokenService = new DefaultTokenServices();
        tokenService.setTokenStore(tokenStore());
        tokenService.setSupportRefreshToken(true);
        tokenService.setClientDetailsService(clientDetailsService);
        tokenService.setTokenEnhancer(jwtAccessTokenConverter());
        tokenService.setReuseRefreshToken(false);
        return tokenService;
    }

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new CustomTokenEnhancer();
        return converter;
    }

    /*
     * Add custom user principal information to the JWT token
     */
    class CustomTokenEnhancer extends JwtAccessTokenConverter {
        @Override
        public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
            User user = (User) authentication.getPrincipal();

            Map<String, Object> info = new LinkedHashMap<String, Object>(accessToken.getAdditionalInformation());

            info.put("username", user.getUsername());
            info.put("email", user.getEmail());
            info.put("roles", user.getRoles());
            info.put("uuid", user.getUuid());
            info.put("device", user.getDevice());

            DefaultOAuth2AccessToken customAccessToken = new DefaultOAuth2AccessToken(accessToken);
            customAccessToken.setAdditionalInformation(info);

            return super.enhance(customAccessToken, authentication);
        }
    }

    class CustomOauth2RequestFactory extends DefaultOAuth2RequestFactory {
        @Autowired
        private TokenStore tokenStore;

        public CustomOauth2RequestFactory(ClientDetailsService clientDetailsService) {
            super(clientDetailsService);
        }

        @Override
        public TokenRequest createTokenRequest(Map<String, String> requestParameters,
                                               ClientDetails authenticatedClient) {
            if (requestParameters.get("grant_type").equals("refresh_token")) {
                OAuth2Authentication authentication = tokenStore.readAuthenticationForRefreshToken(
                        tokenStore.readRefreshToken(requestParameters.get("refresh_token")));
                SecurityContextHolder.getContext()
                        .setAuthentication(new UsernamePasswordAuthenticationToken(authentication.getName(), null,
                                userDetailsService.loadUserByUsername(authentication.getName()).getAuthorities()));
            }

            return super.createTokenRequest(requestParameters, authenticatedClient);
        }
    }

}

@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter implements WebMvcConfigurer {

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new LegacyPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().exceptionHandling().and().cors();
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }

}
Ресурсный сервер
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Profile("!test")
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

    @Value("${auth-server.url}")
    private String authEndpoint;

    @Value("${security.oauth2.client.client-id}")
    private String clientId;

    @Value("${security.oauth2.client.client-secret}")
    private String clientSecret;

    @Override
  public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
    resources.resourceId("ms/legacy");
  }

  @Override
  public void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().anyRequest().permitAll().and().cors().disable().csrf().disable().httpBasic().disable()
        .exceptionHandling()
        .authenticationEntryPoint(
            (request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
        .accessDeniedHandler(
            (request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED));
  }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId("ms/legacy");
    }

    @Bean
    public ResourceServerTokenServices tokenService() {
        RemoteTokenServices tokenServices = new RemoteTokenServices();
        tokenServices.setClientId(clientId);
        tokenServices.setClientSecret(clientSecret);
        tokenServices.setCheckTokenEndpointUrl(authEndpoint + "/uaa/oauth/check_token");
        return tokenServices;
    }
}
...