Spring Cloud Netflix Zuul 路由与帐户服务

如何解决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 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-