Spring Cloud: микросервисная аутентификация работает через Eureka Discovery, но не через Zuul
Я новичок в Spring Cloud. Я пытаюсь создать несколько микросервисов, используя Spring Cloud Eureka Discovery и Zuul Gateway.
Я могу получить доступ к микросервисам и выполнять действия через шлюз Zuul, но только тогда, когда не задействована безопасность. Если мой микросервис защищен, я не могу ничего сделать через Zuul, поскольку он не возвращает токен JWT. Если я делаю это через Eureka Discovery Client, это работает как шарм.
Может быть, что-то не так с моей конфигурацией Zuul? Или, может быть, я выбрал неверный способ защиты услуг? Заранее спасибо!
Вот моя конфигурация шлюза Zuul:
Application.class
@SpringBootApplication
@EnableZuulProxy
@EnableDiscoveryClient
public class GatewayServiceApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayServiceApplication.class, args);
}
@Bean
public Filter shallowEtagHeaderFilter() {
return new ShallowEtagHeaderFilter();
}
}
application.properties
eureka.client.service-url.defaultZone=http://localhost:8010/eureka/
server.port=8011
zuul.prefix=/services
bootstrap.properties
spring.application.name=gateway-service
# specify where config server is up
spring.cloud.config.uri=http://localhost:8001
Вот моя микросервисная JWT и конфигурация безопасности:
WebSecurityConfig.class
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure (HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, "/login").permitAll()
.anyRequest().authenticated()
.and()
// We filter the api/login requests
.addFilterBefore(new JWTLoginFilter("/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class)
// And filter other requests to check the presence of JWT in header
.addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Override
protected void configure (AuthenticationManagerBuilder auth) throws Exception {
// Create a default account
auth.inMemoryAuthentication()
.withUser("**")
.password("**")
.roles("**");
}
}
TokenAuthenticationService.class
public class TokenAuthenticationService {
static final long EXPIRATIONTIME = 864_000_000; // 10 days
static final String SECRET = "*";
static final String TOKEN_PREFIX = "Bearer";
static final String HEADER_STRING = "Authorization";
static void addAuthentication (HttpServletResponse res, String username) {
String JWT = Jwts.builder()
.setSubject(username)
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATIONTIME))
.signWith(SignatureAlgorithm.HS512, SECRET)
.compact();
res.addHeader(HEADER_STRING, TOKEN_PREFIX + " " + JWT);
}
static Authentication getAuthentication (HttpServletRequest request) {
String token = request.getHeader(HEADER_STRING);
if (token != null) {
// parse the token.
String user = Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
.getBody()
.getSubject();
return user != null ?
new UsernamePasswordAuthenticationToken(user, null, Collections.emptyList()) :
null;
}
return null;
}
}
JWTLoginFilter.class
public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter {
public JWTLoginFilter (String url, AuthenticationManager authManager) {
super(new AntPathRequestMatcher(url));
setAuthenticationManager(authManager);
}
@Override
public Authentication attemptAuthentication (HttpServletRequest req, HttpServletResponse res)
throws AuthenticationException, IOException, ServletException {
AccountCredentials creds = new ObjectMapper().readValue(req.getInputStream(), AccountCredentials.class);
return getAuthenticationManager().authenticate(
new UsernamePasswordAuthenticationToken(
creds.getUsername(),
creds.getPassword(),
Collections.emptyList()
)
);
}
@Override
protected void successfulAuthentication (HttpServletRequest req,
HttpServletResponse res,
FilterChain chain,
Authentication auth)
throws IOException, ServletException {
TokenAuthenticationService.addAuthentication(res, auth.getName());
}
}
JWTAuthenticationFilter.class
public class JWTAuthenticationFilter extends GenericFilterBean {
@Override
public void doFilter (ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
Authentication authentication = TokenAuthenticationService.getAuthentication((HttpServletRequest) servletRequest);
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(servletRequest, servletResponse);
}
}
1 ответ
Попробуйте определить ниже.
zuul.sensitiveHeaders=Cookie,Set-Cookie
В zuul заголовки Cookie, Set-Cookie и Authroization являются чувствительными заголовками по умолчанию. Если вы хотите использовать заголовок Authroization на вашем сервере API, вам нужно переопределить его без Authroization
заголовок как выше.
Также вы можете определить его для каждого маршрута. Пожалуйста, обратитесь к документу: http://cloud.spring.io/spring-cloud-netflix/spring-cloud-netflix.html [Cookies и чувствительные заголовки]