百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

spring cloud gateway实现jwt统一认证

haoteby 2024-12-18 14:11 5 浏览

作者 | 坚持坚持

来源 | urlify.cn/VjIZJ3

66套java从入门到精通实战课程分享

当你的项目中服务越来越多,每个服务都有自己的监听地址而又需要把这些服务提供给各式的客户端或第三方使用,那么需要把每个服务地址都暴露出来吗?如果某个服务有多个运行实例,如果进行负载均衡?用户认证和授权需要在每个服务上都做吗,能否统一做?要解决这些问题,就需要用到Api网关,Api网关提供Api请求转发服务并可与Eureka结合实现路由转发和负载均衡,同时利用AOP特性可以实现微服务用户统一认证和授权。目前比较流行的Api网关有Zuul、springcloud gateway以及支持dotnetcore的ocelot。本文使用的是springcloud。

一,搭建springcloud gateway

1,新建一个springboot项目,引入eureka-client和stater-gateway

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

2,项目配置文件:Application.yml

server:
  port: 8020
spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true //启用网关服务发关
          lower-case-service-id: true //支持小写字母的服务名称(注册到eureka的服务)
ek:
  username: eureka
  password: 123456
  eureka-url: 127.0.0.1
  eureka-port: 8765
eureka:
  client:
    service-url:
      defaultZone:
        http://${ek.username}:${ek.password}@${ek.eureka-url}:${ek.eureka-port}/eureka  //Eureka注册地址
  instance:
    prefer-ip-address: true  //启用优先IP地址注册
    instance-id: ${spring.application.name}@${spring.cloud.client.ip-address}@${server.port} //本网关注册到Eureka的实例id

3,启用项目注册到Eureka,并通过网关访问Api 

验证Api

二,DotnetCore JWT证书颁布服务

1,新建一个web api项目,Nuget添加:System.IdentityModel.Tokens.Jwt、Microsoft.IdentityModel.Tokens两个包。配置文件添加jwt配置信息。

appsetting.json 注意:Key用于jwt的签名,长度不能少于16位。可用openssl生成一个32位的密钥。

"Identity": {
   "Jwt": {
     "Key": "1234567890123456",
     "Domain": "kingsun.mico"
   }
 }

使用IOptions读取配置信息并写入依赖

Startup.cs

public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<JwtConfig>(Configuration.GetSection("Identity"));
        services.AddControllers();
    }

2,新建一个名为Token的Api控制器并创建接口GetToken  

[Route("api/[controller]")]
    [ApiController]
    public class TokenController : ControllerBase
    {
        JwtConfig config;
        public TokenController(IOptions< JwtConfig > config)
        {
            this.config = config.Value;
        }
        public class GetTokenRequest
        {
            [Required]
            public string Name { get; set; }
            [Required]
            public string Password { get; set; }
        }
        public class GetTokenRespone
        {
            public int Code { get; set; }
            public string Msg { get; set; }
            public string Data { get; set; }
        }
        [HttpPost("GetToken")]
        public object GetToken([FromBody] GetTokenRequest data)
        {
            GetTokenRespone respone = new GetTokenRespone()
            {
                Code = 0
            };
            if (!ModelState.IsValid)
            {
                respone.Msg = "用户名或密码不能为空";
                return respone;
            }
            //验证密码逻辑
            //....
 
            //jwt中payload键值对内容
            List<Claim> claims = new List<Claim>()
            {
                //用户名
                new Claim("name",data.Name)
            };
            var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(config.Jwt.Key));
            var creds = new SigningCredentials(key,SecurityAlgorithms.HmacSha256);
            var token = new JwtSecurityToken(
                 issuer: "liujb", audience: config.Jwt.Domain, claims: claims, signingCredentials: creds, expires:DateTime.Now.AddDays(1),notBefore:DateTime.Now
                );
            respone.Code = 1;
            respone.Msg = "请求成功";
            respone.Data = new JwtSecurityTokenHandler().WriteToken(token);
            return respone;
        }
    }

3,获取jwt令牌

  

可拿此令牌验证后内容如下:

4,将此服务注册到Eureka后用api网关转发服务获取token:http://localhost:8020/eureka-identity/api/token/gettoken

{
    "code": 1,
    "msg": "请求成功",
    "data": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoibGl1amIiLCJuYmYiOiIxNjAyODE3NjY1MjMwIiwiZXhwIjoiMTYwMjkwNDA2NTIzMCIsImlzcyI6ImxpdWpiIiwiYXVkIjoia2luZ3N1bi5taWNvIn0.5pIrNumEEy280-sCWp4d0K05Skc2Ptn1sK732Rw-L-A"
}

三,在api网关统一做接口认证

1,在第一步建立的网关项目中maven加入java-jwt依赖

<dependency>
           <groupId>com.auth0</groupId>
           <artifactId>java-jwt</artifactId>
           <version>3.11.0</version>
       </dependency>

配置文件加入jwt密钥:jwt.key=1234567890123456。值与第二步的中密钥一致。

2,在该项目新建一个全局过滤器。

@Component
public class JwtFilter implements GlobalFilter, Ordered {
    @Value("${jwt.key}")
    public String jwtKey;
    Logger logger=null;
    public JwtFilter(){
        logger= LoggerFactory.getLogger("JwtFilter");
    }
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String requestUrl=exchange.getRequest().getPath().toString();
        ServerHttpResponse response = exchange.getResponse();
        /*过滤掉获取token的接口*/
        if(requestUrl.toLowerCase().equals("/eureka-identity/api/token/gettoken")){
            return chain.filter(exchange);
        }
        //获取token
        String token=exchange.getRequest().getHeaders().getFirst("Authorization");
        //没有token返回未认证
        if(token==null||token==""){
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        try{
            this.getJwtByToken(token,jwtKey,null);
            return chain.filter(exchange);
        }
        catch(Exception ex){
            logger.error(ex.getMessage());
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
    }
 
    @Override
    public int getOrder() {
        return 0;
    }
    private DecodedJWT getJwtByToken(String token, String key, Map<String,String> claims) throws Exception{
        Algorithm algorithm = Algorithm.HMAC256(key);
        Verification verifier= JWT.require(algorithm)
                .withIssuer("liujb");
        if(claims!=null){
            claims.forEach((mapKey,mapValue)->{
                verifier.withClaim(mapKey,mapValue);
            });}
        JWTVerifier ver= verifier.build();
        DecodedJWT jwt=ver.verify(token);
        return jwt;
    }
}

这里只做了简单的认证,以此基础进行深化,如根据不同的服务名称要求不同的claim。 

3,测试

加入Authorization关,值为之前获取的jwt token

如果token不对或没有token都将返回401状态值

相关推荐

单点登录(SSO)解决方案介绍(单点登录概念)

一、单点登录的介绍单点登录(SingleSignOn),简称为SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系...

系统登录的三种方式,哪一种更安全?

登录是一个高频的动作,笔者抓住这一个小点,分析了系统登录的几种方式和对应的场景。今天谈谈登录。登录即用户输入用户名和密码登录进系统中。B端系统,对于登录的业务场景有两种(可能不止,目前遇到过这两种):...

到底什么是单点登录(SSO)?(什么叫做单点登录)

什么是单点登录?单点登录(SingleSign-On,简称SSO)是一种集中式的身份验证和授权机制,用户只需在一处输入一次凭证(例如用户名和密码)就可以访问多个相关但独立的软件系统。在数字化时代,...

5年稳如老狗的单点登录系统,到底是怎么搞出来的?

说到单点登录(SingleSign-On,简称SSO),大家的第一反应可能是——啊不就是登录一次,能到处串门儿嘛?别说,还真差不多,就是这么个意思。但真要搭一套好用、耐造、还能扛住公司里各种奇奇怪...

这些负载均衡都解决哪些问题?服务、网关、NGINX?

在微服务项目中,有服务的负载均衡、网关的负载均衡、Nginx的负载均衡,这几个负载均衡分别用来解决什么问题呢?一、服务的负载均衡先抛出一个问题:...

Nginx负载均衡最全详解(4大算法原理机制)

Nginx在大型网站架构很重要,也是大厂重点考察方向,今天我就重点来详解Nginx负载均衡@mikechen本篇已收于mikechen原创超30万字《阿里架构师进阶专题合集》里面。Nginx负载均衡N...

负载均衡 Nginx Session 一致性(nginx 负载均衡 会话保持)

HTTPS请求跳转...

监控Oracle Cloud负载均衡器:Applications Manager释放最佳性能

设想你正在运营一个受欢迎的在线学习平台,在考试前的高峰期,平台流量激增。全球的学生同时登录,观看视频、提交作业和参加测试。如果OracleCloud负载均衡器不能高效地分配流量,或者后端服务器难...

Nginx负载均衡:nginx.conf配置文件说明!

大家好,欢迎来到程序视点!我是你们的老朋友.小二!在此记录下Nginx服务器nginx.conf负载均衡的配置文件说明,部分注释收集与网络.关于nginx.conf基本的配置,请查看上一篇文章!Ng...

Java高可用系统架构中的负载均衡策略

Java高可用系统架构中的负载均衡策略在现代的分布式系统中,负载均衡策略是构建高可用系统的基石。Java开发者需要深刻理解这些策略,以便打造稳定且高效的系统。接下来,让我们一起揭开负载均衡的神秘面纱。...

深入对比Nginx、LVS和HAProxy,选择最合适负载均衡方案!

关注...

Spring Boot3 客户端负载均衡全解析:从原理到实战

在当今互联网大厂后端技术开发的激烈竞争环境中,构建高效、稳定的微服务架构是核心诉求。其中,SpringBoot3作为热门开发框架,其客户端负载均衡功能对于提升系统性能、保障服务稳定性起着关键作用。...

MySql高可用集群MySQL Router负载均衡读写分离

名词解释MGR:MysqlGroupReplication组复制,多台MySQL服务器在同一组中会自动保持同步状态,当某台服务器故障时,整个复制组依然可以保持正常并对外提供服务。...

性能测试之tomcat+nginx负载均衡(nginx tomcat)

nginxtomcat配置准备工作:两个tomcat执行命令cp-rapache-tomcat-8.5.56apache-tomcat-8.5.56_2修改被复制的tomcat2下con...

win10/11双网卡链路聚合叠加负载均衡提升网速解决网卡网速瓶颈!

双网卡链路聚合一种网络配置技术,通过将多个物理网卡绑定在一起,形成一个逻辑上的网络接口,以提高网络的可靠性、可用性和性能。这种技术通常用于服务器和网络设备中,以实现负载均衡、冗余和高可用性。本机环境:...