Симулировать пользовательский перехватчик клиента для проверки токена JWT

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

Есть ли такие пользовательские перехватчики для обработки токенов, генерируемых именем пользователя и паролем?

2 ответа

Если ваш поставщик токенов JWT совместим с OAuth 2.0, вы можете настроить OAuth2FeignRequestInterceptor, с OAuth2ProtectedResourceDetails объект. Этот объект является базовым классом для всей информации о типе предоставления OAuth 2.0. В вашем случае я рекомендую использовать ResourceOwnerPasswordResourceDetails вместо. Это позволит вам настроить перехватчик, используя имя пользователя и пароль.

@Configuration
public class OAuth2RequestInterceptorConfiguration {

    @Bean
    public OAuth2FeignRequestInterceptor requestInterceptor() {
        OAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
        OAuth2ProtectedResourceDetails resourceDetails =
            new ResourceOwnerPasswordResourceDetails();
        resourceDetails.setUsername("username");
        resourceDetails.setPassword("password");
        return new OAuth2FeignRequestInterceptor(clientContext, resourceDetails);
    }
}

В других случаях вам нужно будет создать свой собственный RequestInterceptor

public class MyRequestInterceptor implements RequestInterceptor {

    private String jwt;
    private LocalDateTime expirationDate;

    @Override
    public void apply(RequestTemplate requestTemplate) {
        /* validate and refresh your token, this sample is not thread safe */
        if (LocalDateTime.now().isAfter(expirationDate)) {
            requestToken();
        }

        /* use the token */
        requestTemplate.header("Authorization: Bearer " + this.jwt);
    }
}

Вы можете попробовать что-то вроде:

public class FeignConfiguration {

    @Value("${security.jwt.token}")
    private String jwtToken;

    @Bean
    public RequestInterceptor requestInterceptor() {
        @Override
        public void apply(RequestTemplate requestTemplate) {
            requestTemplate.header("Authorization", jwtToken);
        }
    }
}

Не совсем понятен вариант использования, но, возможно, следующий фрагмент кода будет также полезен. Наш сервис ожидает подписанный токен доступа OAuth Bearer JWT. Вы можете видеть, что мы проверяем явно по истечении срока действия JWT и возвращаем ошибку, когда истекает срок действия токена JWT. В нашей настройке ответственность за обнаружение этой ошибки и использование токена обновления (для получения нового токена доступа) лежит на потребителе в случае возникновения такого сценария.

Надеюсь, это прояснит немного.

Wim

/**
 * Created by Wim Van den Brande on 11/02/2018.
 */
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private static final Logger LOGGER = LoggerFactory.getLogger(SecurityConfig.class);

    public static final String SCOPE = "scope";
    public static final String HEADER_AUTHORIZATION = "Authorization";
    public static final String HEADER_BEARER = "Bearer";
    public static final String HEADER_ENCRYPTION_TYPE = "Encryption-Type";
    public static final String ASSYMETRIC_ENCRYPTION_RS256 = "RS256";

    @Value("${CS.signedPublicKey}")
    private String signedPublicKey;

    @Autowired
    private Key signinKey;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // TODO : to enable CSRF
        http.httpBasic().and().csrf().disable();

        TokenAuthenticationFilter tokenFilter = new TokenAuthenticationFilter();
        http.addFilterBefore(tokenFilter, BasicAuthenticationFilter.class);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/admin", "/v2/api-docs", "/configuration/ui", "/swagger-resources", "/configuration/security", "/swagger-ui.html", "/webjars/**");
    }

    // Actual Implementation of Token Based Authentication
    // ---------------------------------------------------
    public class TokenAuthenticationFilter extends GenericFilterBean {

        @Override
        public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
            final HttpServletRequest httpRequest = (HttpServletRequest) request;
            final HttpServletResponse httpResponse = (HttpServletResponse) response;

            String authorizationHeader = httpRequest.getHeader(HEADER_AUTHORIZATION);

            if (authorizationHeader == null) {
                    httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, String.format("Request doesn't contain header %s.", HEADER_AUTHORIZATION));
                    return;
            }

            String[] authorizationHeaderValues = authorizationHeader.split("\\s+");

            if (authorizationHeaderValues.length != 2 || !authorizationHeaderValues[0].equals(HEADER_BEARER)) {
                httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, String.format("AuthorizationHeader %s is an invalid header ", authorizationHeader));
                return;
            }

            String accessToken = authorizationHeaderValues[1];
            Claims jwtClaims;

            // Symmetric Encryption is our default

            if (httpRequest.getHeader(HEADER_ENCRYPTION_TYPE) == null || !httpRequest.getHeader(HEADER_ENCRYPTION_TYPE).equals(ASSYMETRIC_ENCRYPTION_RS256)) {
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Using Symmetric algorithm");
                }

                try {
                    jwtClaims = Jwts.parser().setSigningKey(signinKey).parseClaimsJws(accessToken).getBody();
                }
                catch (ExpiredJwtException e) {
                    httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "JSON Web Token has expired");
                    return;
                }
            }

введите код сюда

Другие вопросы по тегам