如何解决Spring Cloud Netflix Zuul 路由与帐户服务
我正在开发一个微服务网络应用程序。
我有这个微服务:
- 前端服务(所有 html 文件)
- 账户服务(使用 Spring Security)
- ZuulGateway 服务
- 演示服务(返回字符串的简单休息控制器)
- EurekaServer 服务
我的帐户服务有效。登录阶段有效,JWT 创建有效。我将它保存在响应的标题中:
response.addHeader("Authorization","Bearer " + token);
这是前端的Ajax代码:
/* sign in submit function */
$("#submit").click(function(e) {
e.preventDefault();
$.ajax({ /* Ajax call to AccountMicroservice for login */
url : 'http://localhost:8762/token/generate-token',type : "POST",data : {
username : $("#username").val(),password : $("#password").val()
},success : function(data) {
console.log(data.token);
window.location.href = 'http://localhost:8762/test';
},error : function(result) {
alert("Sign in failed!");
console.log(result);
}
});
});
问题随着 Spring Cloud Netflix Zuul 的加入而出现。网关服务器端口为 8762。 对“http://localhost:8762/token/generate-token”的每个请求都会返回 401 错误。
这些是 Zuul 网关服务。 我省略了导入。
application.properties:
server.port=8762
spring.application.name=gateway-service
eureka.client.serviceUrl.defaultZone=${EUREKA_SERVER_URL:http://localhost:8761/eureka}
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
zuul.routes.test-service.path=/test/**
zuul.routes.test-service.service-id=test-service
zuul.routes.account-service.path=/token/**
zuul.routes.account-service.service-id=account-service
zuul.routes.auth-service.sensitive-headers=Cookie,Set-Cookie
webSecurityConfig:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler)
.and()
.addFilterAfter(new JwtTokenAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
// allow all who are accessing "auth" service
.antMatchers(HttpMethod.POST,"/token/**","/signup").permitAll()
// Any other request must be authenticated
.anyRequest().authenticated();
}
//The CORS filter bean - Configures allowed CORS any (source) to any
//(api route and method) endpoint
@Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin(CorsConfiguration.ALL);
//config.addAllowedHeaders(Collections.singletonList(CorsConfiguration.ALL));
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**",config);
return source;
}
}
JwtTokenUtil:
@Component
public class JwtTokenUtil implements Serializable {
public String getUsernameFromToken(String token) {
return getClaimFromToken(token,Claims::getSubject);
}
public Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token,Claims::getExpiration);
}
public <T> T getClaimFromToken(String token,Function<Claims,T> claimsResolver) {
final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims);
}
private Claims getAllClaimsFromToken(String token) {
return Jwts.parser()
.setSigningKey(SIGNING_KEY)
.parseClaimsJws(token)
.getBody();
}
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
public String generateToken(Authentication authentication) {
final String authorities = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(","));
return Jwts.builder()
.setSubject(authentication.getName())
.claim(AUTHORITIES_KEY,authorities)
.signWith(SignatureAlgorithm.HS256,SIGNING_KEY)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + ACCESS_TOKEN_VALIDITY_SECONDS*1000))
.compact();
}
public Boolean validateToken(String token,UserDetails userDetails) {
final String username = getUsernameFromToken(token);
return (
username.equals(userDetails.getUsername())
&& !isTokenExpired(token));
}
UsernamePasswordAuthenticationToken getAuthentication(final String token,final Authentication existingAuth,final UserDetails userDetails) {
final JwtParser jwtParser = Jwts.parser().setSigningKey(SIGNING_KEY);
final Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
final Claims claims = claimsJws.getBody();
final Collection<? extends GrantedAuthority> authorities =
Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
return new UsernamePasswordAuthenticationToken(userDetails,"",authorities);
}
}
JwtTokenAuthenticationFilter:
public class JwtTokenAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Override
protected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain chain) throws ServletException,IOException {
// 1. get the authentication header. Tokens are supposed to be passed in the authentication header
String header = request.getHeader(HEADER_STRING);
String username = null;
String authToken = null;
// 2. validate the header and check the prefix
if (header != null && header.startsWith(TOKEN_PREFIX)) {
// 3. Get the token
authToken = header.replace(TOKEN_PREFIX,"");
try {
username = jwtTokenUtil.getUsernameFromToken(authToken);
System.out.println("\n\n\n\n\n\n\n\n\n\n" + username + "\n\n\n\n\n\n\n\n\n\n");
} catch (IllegalArgumentException e) {
logger.error("c'è stato un errore durante il reperimento dello username dal token",e);
}
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
// 4. Validate the token
if (jwtTokenUtil.validateToken(authToken,userDetails)) {
//UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails,null,Arrays.asList(new SimpleGrantedAuthority("ROLE_ADMIN")));
UsernamePasswordAuthenticationToken authentication = jwtTokenUtil.getAuthentication(authToken,SecurityContextHolder.getContext().getAuthentication(),userDetails);
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
logger.info("authenticated user " + username + ",setting security context");
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
// go to the next filter in the filter chain
chain.doFilter(request,response);
}
}
JwtAuthenticationEntryPoint:
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint,Serializable {
@Override
public void commence(HttpServletRequest request,AuthenticationException authException) throws IOException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,"Unauthorized");
String json = String.format("{\"message\": \"%s\"}",authException.getMessage());
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(json);
}
}
常量:
public class Constants {
public static final long ACCESS_TOKEN_VALIDITY_SECONDS = 5*60*60;
public static final String SIGNING_KEY = "devglan123r";
public static final String TOKEN_PREFIX = "Bearer ";
public static final String HEADER_STRING = "Authorization";
public static final String AUTHORITIES_KEY = "scopes";
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。