8.15日学习打卡---Spring Cloud Alibaba(三)

发布于:2024-08-15 ⋅ 阅读:(57) ⋅ 点赞:(0)

8.15日学习打卡

在这里插入图片描述

为什么需要服务网关

传统的单体架构中只需要开放一个服务给客户端调用,但是微服务架构中是将一个系统拆分成多个微服务,如果没有网关,客户端只能在本地记录每个微服务的调用地址,当需要调用的微服务数量很多时,它需要了解每个服务的接口,这个工作量很大。
在这里插入图片描述
服务网关的基本功能
在这里插入图片描述

微服务网关的作用:

  • 提供了统一访问入口,降低了服务受攻击面
  • 提供了统一跨域解决方案
  • 提供了统一日志记录操作,可以进行统一监控
  • 提供了统一权限认证支持
  • 提供了微服务限流功能,可以保护微服务,防止雪崩效应发生

主流网关的对比与选型

  • Kong 网关:Kong 的性能非常好,非常适合做流量网关,但是对于复杂系统不建议业务网关用 Kong,主要是工程性方面的考虑
  • Zuul1.x 网关:Zuul 1.0 的落地经验丰富,但是性能差、基于同步阻塞IO,适合中小架构,不适合并发流量高的场景,因为容易产生线程耗尽,导致请求被拒绝的情况
  • gateway 网关:功能强大丰富,性能好,官方基准测试 RPS (每秒请求数)是Zuul的1.6倍,能与 SpringCloud 生态很好兼容,单从流式编程+支持异步上也足以让开发者选择它了。
  • Higress:一个遵循开源Ingress/Gateway API标准,提供流量调度、服务治理、安全防护三合一的高集成、易使用、易扩展、热更新的下一代云原生网关。

Higress是什么

在这里插入图片描述
Higress是什么
Higress是基于阿里内部的Envoy Gateway实践沉淀、以开源Istio + Envoy为核心构建的下一代云原生网关,实现了流量网关 + 微服务网关 + 安全网关三合一的高集成能力,深度集成Dubbo、Nacos、Sentinel等微服务技术栈,能够帮助用户极大的降低网关的部署及运维成本且能力不打折。
在这里插入图片描述
传统网关分类
行业中通常把网关分为两个大类:流量网关与业务网关,流量网关主要提供全局性的、与后端业务无关的策略配置,例如阿里内部的的统一接入网关Tengine就是典型的流量网关;业务网关顾名思义主要提供独立业务域级别的、与后端业务紧耦合策略配置,随着应用架构模式从单体演进到现在的分布式微服务,业务网关也有了新的叫法 - 微服务网关(图示说明如下)。在目前容器技术与K8s主导的云原生时代,下一代网关模式依然是这样吗?

在这里插入图片描述
Higress定位
在虚拟化时期的微服务架构下,业务通常采用流量网关 + 微服务网关的两层架构,流量网关负责南北向流量调度和安全防护,微服务网关负责东西向流量调度和服务治理,而在容器和 K8s 主导的云原生时代,Ingress 成为 K8s 生态的网关标准,赋予了网关新的使命,使得流量网关 + 微服务网关合二为一成为可能。
在这里插入图片描述

安装DockerCompose

在这里插入图片描述
关闭防火墙

systemctl stop firewalld

设置安装仓库

#安装yum的工具包
yum install -y yum-utils \
      device-mapper-persistent-data \
      lvm2 --skip-broken
#更新本地镜像源
# 设置docker镜像源
yum-config-manager \
  --add-repo \
   https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
  
sed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/yum.repos.d/docker-ce.repo
#将软件包信息提前在本地索引缓存,用来提高搜索安装软件的速度,建议执行这个命令可以提升yum安装的速度。
yum makecache fast

安装docker引擎

sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y

启动docker

systemctl start docker

设置docker自启动

systemctl enable docker

测试docker是否安装成功

docker run hello-world

部署Higress

在这里插入图片描述
搭建Higress
在安装之前要保证Docker安装成功并且成功安装Docker Copmpose插件。

curl -fsSL https://higress.io/standalone/get-higress.sh | bash -s -- -c nacos://192.168.47.100:8848 --nacos-username=nacos --nacos-password=nacos -p <你的密码>

在这里插入图片描述

启动成功后,本机端口占用情况如下:

80端口:Higress 暴露,用于 HTTP 协议代理
443端口:Higress 暴露,用于 HTTPS 协议代理
15020端口:Higress 暴露,用于暴露 Prometheus 指标
8080端口:Higress 控制台 暴露,(admin/123456)

Higress命令
在这里插入图片描述

命令解释:

startup.sh : 启动Higress
shutdown.sh : 停止Higress
configure.sh : 配置nacos地址

访问Higress控制台

在浏览器中输入http://127.0.0.1:8080,使用用户名 admin 和安装时设置的密码登录 Higress 控制台。
在这里插入图片描述

创建网关微服务模块

创建子模块 jjy-order-higress

引入依赖包

 <!--   springboot依赖包-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>


    <!--   nacos依赖包  -->
    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>

编写配置文件
在resources文件夹下面创建application.yml文件。

spring:
  application:
  # 应用名字
   name: order-service
  cloud:
   nacos:
    discovery:
    # Nacos注册中心的地址
     server-addr:  192.168.47.100:8848
server:
  port: 8006

编写主启动类
在com.jjy文件夹下面创建OrderHigressAppcation主启动类。

/**
 * 主启动类
 */
@Slf4j
@EnableDiscoveryClient
@SpringBootApplication
public class OrderAppcation
{
  public static void main( String[] args )
   {
    SpringApplication.run(OrderAppcation.class,args);
    log.info("****************** 订单微服务启动成功 ***********");
   }
}

编写测试控制器

package com.jjy.controller;


import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class IndexController {


  @GetMapping("/index")
  public String index(){
    return "hello  higress";
   }

}


Higress路由配置

在这里插入图片描述
什么是路由

在微服务架构中,路由是一种用于管理和定向请求流量的重要机制。微服务架构将一个应用程序拆分成一组小型、独立的服务,每个服务专注于执行特定的业务功能。路由在这样的环境中起到了指导请求流向的作用。
在这里插入图片描述
安装Switchhosts
SwitchHosts是一款便捷且免费的软件,体积为8M左右,不会占用电脑过多的内存,并且默认就是绿色软件,带有简体中文界面,在windows7、xp与vista等系统中能够运行。

该软件主要带有两个功能:

切换hosts与编辑hosts。
在这里插入图片描述
设置域名
在这里插入图片描述
创建路由
配置支付服务路由规则。
在这里插入图片描述
设置路由策略
在这里插入图片描述
重写地址

在这里插入图片描述
请求验证
执行以下命令,验证测试路由可以正常工作:

# should output a JSON object containing request data 
curl http://www.it.com/payment/index

Higress策略配置-跨域配置

为什么会出现跨域问题

出于浏览器的同源策略限制。同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

什么是跨域
当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域

当前页面url 被请求页面url 是否跨域 原因
http://www.test.com/ http://www.test.com/index.html 同源(协议、域名、端口号相同)
http://www.test.com/ https://www.test.com/index.html 跨域 协议不同(http/https)
http://www.test.com/ http://www.baidu.com/ 跨域 主域名不同(test/baidu)
http://www.test.com/ http://blog.test.com/ 跨域 子域名不同(www/blog)
http://www.test.com:8080/ http://www.test.com:7001/ 跨域 端口号不同(8080/7001)

跨域问题演示
在resources中创建templates文件夹,在编写index页面

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>


</body>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>
  $.get("http://www.it.com/order/index",function(data,status){
    alert("Data: " + data );
   });
</script>
</html>

Higress解决如何允许跨域

CORS

  • 如何允许跨域,一种解决方法就是目的域告诉请求者允许什么来源域来请求,那么浏览器就会知道B域是否允许A域发起请求。
  • CORS(“跨域资源共享”(Cross-origin resource sharing))就是这样一种解决手段。

CORS使得浏览器在向目的域发起请求之前先发起一个OPTIONS方式的请求到目的域获取目的域的信息,比如获取目的域允许什么域来请求的信息。

Higress策略配置之什么是HTTP认证

概述
HTTP认证是一种用于保护Web应用程序的一种身份验证机制。它通过在HTTP请求的头部添加认证信息,来验证用户的身份和权限。HTTP认证可以用于保护敏感信息,限制访问某些资源,或者在访问某些操作之前要求用户提供凭据。

HTTP 基本认证

常见的验证方案包括
1、Basic Authentication(基本认证)
Basic认证是最常见的HTTP认证方式之一。在Basic认证中,客户端发送请求时,会在请求头中包含一个"Authorization"字段,该字段包含了经过Base64编码的用户名和密码。

2、Digest Authentication(摘要认证)
Digest认证是一种更安全的认证方式。在Digest认证中,服务器会向客户端发送一个随机数(称为"nonce"),客户端根据该随机数和用户密码计算一个摘要,并将其发送给服务器。服务器收到摘要后,会验证其有效性。Digest认证相对于Basic认证而言,更难以被中间人攻击截获密码。

3、Bearer Token Authentication(令牌认证)
Bearer认证是一种使用令牌(Token)进行身份验证的方式。在Bearer认证中,客户端在请求头中添加一个"Authorization"字段,该字段包含了一个令牌信息。服务器在接收到请求后,会验证令牌的有效性,并根据令牌来识别用户身份。

4、OAuth(开放授权)
OAuth认证是一种开放标准的身份验证协议,用于授权第三方应用程序访问用户资源。在OAuth认证中,用户可以通过授权服务器授权第三方应用程序访问自己的资源。这种方式可以避免用户将密码直接提供给第三方应用程序。

Higress策略配置-Basic 认证

在这里插入图片描述
Basic 概述
Basic 认证是HTTP 中非常简单的认证方式,因为简单,所以不是很安全,不过仍然非常常用。当一个客户端向一个需要认证的HTTP服务器进行数据请求时,,HTTP服务器会返回401状态码,要求客户端输入用户名和密码。用户输入用户名和密码后,用户名和密码会经过BASE64加密附加到请求信息中再次请求HTTP服务器,HTTP服务器会根据请求头携带的认证信息,决定是否认证成功及做出相应的响应。

在这里插入图片描述
功能说明

basic-auth插件实现了基于 HTTP Basic Auth 标准进行认证鉴权的功能

配置字段
全局配置

名称 数据类型 填写要求 默认值 描述
consumers array of object 必填 - 配置服务的调用者,用于对请求进行认证
global_auth bool 选填 - 若配置为true,则全局生效认证机制; 若配置为false,则只对做了配置的域名和路由生效认证机制; 若不配置则仅当没有域名和路由配置时全局生效(兼容机制)

consumers中每一项的配置字段说明如下:

名称 数据类型 填写要求 默认值 描述
credential string 必填 - 配置该consumer的访问凭证
name string 必填 - 配置该consumer的名称

域名和路由级配置

名称 数据类型 填写要求 默认值 描述
allow array of string 必填 - 对于符合匹配条件的请求,配置允许访问的consumer名称

注意:

  • 对于通过认证鉴权的请求,请求的header会被添加一个X-Mse-Consumer字段,用以标识调用者的名称。

配置示例
1、对特定路由或域名开启认证和鉴权

以下配置将对网关特定路由或域名开启 Basic Auth 认证和鉴权,注意凭证信息中的用户名和密码之间使用":"分隔,credential字段不能重复。

全局配置

consumers:
- credential: 'admin:123456'
  name: consumer1
- credential: 'guest:abc'
  name: consumer2
global_auth: false

路由级配置

对 route-a 和 route-b 这两个路由做如下配置:

allow: 
- consumer1

若是在控制台进行配置,此例指定的 route-aroute-b 即在控制台创建路由时填写的路由名称,当匹配到这两个路由时,将允许nameconsumer1的调用者访问,其他调用者不允许访问;此例指定的 *.example.comtest.com 用于匹配请求的域名,当发现域名匹配时,将允许nameconsumer2的调用者访问,其他调用者不允许访问。

测试配置

在这里插入图片描述
相关错误码

HTTP 状态码 出错信息 原因说明
401 Request denied by Basic Auth check. No Basic Authentication information found. 请求未提供凭证
401 Request denied by Basic Auth check. Invalid username and/or password 请求凭证无效
403 Request denied by Basic Auth check. Unauthorized consumer 请求的调用方无访问权限

什么是JWT认证

JWT (全称:Json Web Token)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为 JSON 对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。官方网址https://jwt.io/

传统的session认证
Session 的认证流程通常会像这样:
在这里插入图片描述

缺点:

安全性:CSRF攻击因为基于cookie来进行用户识别, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。
扩展性:对于分布式应用,需要实现 session 数据共享
性能:每一个用户经过后端应用认证之后,后端应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大,与REST风格不匹配。因为它在一个无状态协议里注入了状态。

JWT方式

在这里插入图片描述

优点:

  • 无状态
  • 适合移动端应用
  • 单点登录友好

JWT原理

JWT 的原理是,服务器认证以后,生成一个 JSON 对象,发回给用户,就像下面这样

{
  "姓名": "张三",
  "角色": "管理员",
  "到期时间": "2030年7月1日0点0分"
}

注意:

用户与服务端通信的时候,都要发回这个 JSON
对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候会加上签名,服务器就不保存任何 session
数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。

JWT 结构
一个 JWT 实际上就是一个字符串,它由三部分组成:头部、载荷与签名。中间用点 . 分隔成三个部分。注意 JWT 内部是没有换行的。
在这里插入图片描述
头部 / header

JSON对象,描述 JWT 的元数据。其中 alg 属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ 属性表示这个令牌(token)的类型(type),统一写为 JWT。

{
 "alg": "HS256",
 "typ": "JWT"
}

注意:

上面代码中,alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT然后将头部进行Base64编码构成了第一部分,Base64是一种用64个字符来表示任意二进制数据的方法,Base64是一种任意二进制到文本字符串的编码方法,常用于在URL、Cookie、网页中传输少量二进制数据。

载荷 / Payload

Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 指定七个默认字段供选择。除了默认字段之外,你完全可以添加自己想要的任何字段,一般用户登录成功后,就将用户信息存放在这里

iss:发行人
exp:到期时间
sub:主题
aud:用户
nbf:在此之前不可用
iat:发布时间
jti:JWT ID用于标识该JWT
{
 "iss": "xxxxxxx",
 "sub": "xxxxxxx",
 "aud": "xxxxxxx",
 "user": {
     'username': 'itbaizhan',
     'userId': 1
  } 
}

签名 / Signature

  • 签名部分是对上面的 头部、载荷 两部分数据进行的数据签名
  • 为了保证数据不被篡改,则需要指定一个密钥,而这个密钥一般只有你知道,并且存放在服务端
  • 生成签名的代码一般如下:
// 其中secret 是密钥
String signature = HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

JWT 的使用方式
在这里插入图片描述

流程:

客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在
localStorage。此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie
里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息Authorization字段里面。

创建认证中心微服务

认证微服务模块
引入依赖

<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <dependency>
      <groupId>org.bitbucket.b_c</groupId>
      <artifactId>jose4j</artifactId>
      <version>0.7.0</version>
    </dependency>
    <dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>5.8.18</version>
    </dependency>
  </dependencies>

创建配置文件
在resources文件夹下面创建application.yml文件。

spring:
  application:
  # 应用名字
   name: auth-service
  cloud:
   nacos:
    discovery:
    # Nacos注册中心的地址
     server-addr:  192.168.47.100:8848
server:
  port: 8989

创建主启动类

@SpringBootApplication
@Slf4j
public class AuthApplication
{
  public static void main( String[] args ) throws JoseException {
    SpringApplication.run(AuthApplication.class,args);
    log.info("*****************  认证授权中心启动成功 **************");
   }
}

编写JWT工具类生成jwt

引入依赖

<dependency>
   <groupId>org.bitbucket.b_c</groupId>
   <artifactId>jose4j</artifactId>
   <version>0.7.0</version>
</dependency>

生成公钥和私钥

RsaJsonWebKey rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
    final String publicKeyString = rsaJsonWebKey.toJson(JsonWebKey.OutputControlLevel.PUBLIC_ONLY);
    final String privateKeyString = rsaJsonWebKey.toJson(JsonWebKey.OutputControlLevel.INCLUDE_PRIVATE);
    System.out.println(publicKeyString);
    System.out.println(privateKeyString);

生成token

 // 创建claims,这将是JWT的内容 B部分
    JwtClaims claims = new JwtClaims();
    // 谁创建了令牌并签署了它
    claims.setIssuer("abcd");
    // 令牌将被发送给谁
    claims.setAudience("Audience");
    // 令牌失效的时间长(从现在开始10分钟)
    claims.setExpirationTimeMinutesInTheFuture(10);
    // 令牌的唯一标识符
    claims.setGeneratedJwtId();
    // 当令牌被发布/创建时(现在)
    claims.setIssuedAtToNow();
    // 在此之前,令牌无效(2分钟前)
    claims.setNotBeforeMinutesInThePast(2);
    // 主题 ,是令牌的对象
    claims.setSubject("subject");
    // 可以添加关于主题的附加 声明/属性
    claims.setClaim("userId", userId);
    claims.setClaim("username", username);
    // JWT是一个JWS和/或一个带有JSON声明的JWE作为有效负载。
    // 在这个例子中,它是一个JWS,所以我们创建一个JsonWebSignature对象。
    JsonWebSignature jws = new JsonWebSignature();


    // JWS的有效负载是JWT声明的JSON内容
    jws.setPayload(claims.toJson());
    System.out.println(claims.toJson());


    PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(privatekey)).getPrivateKey();
    // JWT使用私钥签署
    jws.setKey(privateKey);


    /*
     * 设置关键ID(kid)头,因为这是一种礼貌的做法。 在这个例子中,我们只有一个键但是使用键ID可以帮助
     * 促进平稳的关键滚动过程
     */
    jws.setKeyIdHeaderValue("keyId");


    // 在jw/jws上设置签名算法,该算法将完整性保护声明
    jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);


    /*
     * 签署JWS并生成紧凑的序列化或完整的jw/JWS 表示,它是由三个点('.')分隔的字符串
     * 在表单头.payload.签名中使用base64url编码的部件 如果你想对它进行加密,你可以简单地将这个jwt设置为有效负载
     * 在JsonWebEncryption对象中,并将cty(内容类型)头设置为“jwt”。
     */
    String jwt = jws.getCompactSerialization();


    // 现在你可以用JWT做点什么了。比如把它寄给其他的派对
    // 越过云层,穿过网络。
    System.out.println("JWT: " + jwt);
    return jwt;

编写JWT工具类解密Token

public static void checkJwt(String jwt) throws MalformedClaimException, JoseException {
    /*
     * 使用JwtConsumer builder构建适当的JwtConsumer,它将 用于验证和处理JWT。 JWT的具体验证需求是上下文相关的, 然而,
     * 通常建议需要一个(合理的)过期时间,一个受信任的时间 发行人, 以及将你的系统定义为预期接收者的受众。
     * 如果JWT也被加密,您只需要提供一个解密密钥对构建器进行解密密钥解析器。
     */


    PublicKey publicKey1 = new RsaJsonWebKey(JsonUtil.parseJson(publicKey)).getRsaPublicKey();


    JwtConsumer jwtConsumer = new JwtConsumerBuilder().setRequireExpirationTime()
         .setAllowedClockSkewInSeconds(30) // 允许在验证基于时间的令牌时留有一定的余地,以计算时钟偏差。单位/秒
         .setRequireSubject() // 主题声明
         .setExpectedIssuer("Issuer") // JWT需要由谁来发布,用来验证 发布人
         .setExpectedAudience("Audience") // JWT的目的是给谁, 用来验证观众
         .setVerificationKey(publicKey1) // 用公钥验证签名 ,验证秘钥
         .setJwsAlgorithmConstraints( // 只允许在给定上下文中预期的签名算法,使用指定的算法验证
            new AlgorithmConstraints(ConstraintType.WHITELIST, // 白名单
                AlgorithmIdentifiers.RSA_USING_SHA256))
         .build(); // 创建JwtConsumer实例
    try {
      // 验证JWT并将其处理为jwtClaims
      JwtClaims jwtClaims = jwtConsumer.processToClaims(jwt);
//          如果JWT失败的处理或验证,将会抛出InvalidJwtException。
//          希望能有一些有意义的解释(s)关于哪里出了问题。
      System.out.println("JWT validation succeeded! " + jwtClaims);
     } catch (InvalidJwtException e) {
      System.out.println("Invalid JWT! " + e);
      // 对JWT无效的(某些)特定原因的编程访问也是可能的
      // 在某些情况下,您是否需要不同的错误处理行为。
      // JWT是否已经过期是无效的一个常见原因
      if (e.hasExpired()) {
        System.out.println("JWT expired at " + e.getJwtContext().getJwtClaims().getExpirationTime());
       }
      // 或者观众是无效的
      if (e.hasErrorCode(ErrorCodes.AUDIENCE_INVALID)) {
        System.out.println("JWT had wrong audience: " + e.getJwtContext().getJwtClaims().getAudience());
       }
     }
   }

认证中心微服务颁发Token令牌

编写认证中心控制器
创建controller包,在controller里面新建AuthController接口。

@RestController
public class AuthController {


  @Autowired
  SysLoginService sysLoginService;


  @PostMapping("login")
  public R<?> login(@RequestBody LoginBody form) throws MalformedClaimException, JoseException {
    return sysLoginService.login(form.getUsername(), form.getPassword());
   }


}

编写统一结果返回集

package com.jjy.domian;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;


/**
 * 统一结果返回集
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class R {


  // 状态码
  private int code;


  // 返回信息
  private String meg;


  // 数据
  private Object data;


  public static R fail(String meg){
    R r = new R();
    r.setCode(500);
    r.setMeg(meg);
    return r;
   }
  public static R ok(Object data){
    R r = new R();
    r.setCode(200);
    r.setMeg("sucess");
    r.setData(data);
    return r;
   }
}

登录业务层

package com.jjy.service;


import com.alibaba.nacos.common.utils.StringUtils;
import com.itbaizhan.domian.LoginBodyDTO;
import com.itbaizhan.domian.R;
import com.itbaizhan.utils.JwtUtils;
import org.jose4j.lang.JoseException;
import org.springframework.stereotype.Service;


@Service
public class SysLoginService {




  /**
   * 登录
   * @param loginBodyDTO
   * @return
   */
  public R login(LoginBodyDTO loginBodyDTO) throws JoseException {
    // 1、用户名或者密码校验
    if (StringUtils.isEmpty(loginBodyDTO.getUsername()) || StringUtils.isEmpty(loginBodyDTO.getPassword()) ){
      return R.fail("用户名或者密码为空");
     }
    // 2、判断用户名和密码是否正确
    //TODO 数据库操作
    if (loginBodyDTO.getUsername().equals("admin")&& loginBodyDTO.getPassword().equals("123456")){
      // 颁发登录token
      String token = JwtUtils.sign(1001L, "admin");
      return R.ok(token);
     }else {
      return R.fail("用户名或者密码不对");
     }
   }


}

JWT配置

在这里插入图片描述
基于Token的认证

很多对外开放的API需要识别请求者的身份,并据此判断所请求的资源是否可以返回给请求者。token就是一种用于身份验证的机制,基于这种机制,应用不需要在服务端保留用户的认证信息或者会话信息,可实现无状态、分布式的Web应用授权,为应用的扩展提供了便利。
在这里插入图片描述

业务流程:

1.客户端向API网关发起认证请求,请求中一般会携带终端用户的用户名和密码;
2.网关将请求直接转发给后端服务;
3.后端服务读取请求中的验证信息(比如用户名、密码)进行验证,验证通过后使用私钥生成标准的token,返回给网关;
4.网关将携带token的应答返回给客户端,客户端需要将这个token缓存到本地;
5.客户端向API网关发送业务请求,请求中携带token;
6.网关使用用户设定的公钥对请求中的token进行验证,验证通过后,将请求透传给后端服务;
7.后端服务进行业务处理后应答;
8.网关将业务应答返回给客户端。

功能说明
jwt-auth插件实现了基于JWT(JSON Web Tokens)进行认证鉴权的功能,支持从HTTP请求的URL参数、请求头、Cookie字段解析JWT,同时验证该Token是否有权限访问。

配置字段
全局配置

名称 数据类型 填写要求 默认值 描述
consumers array of object 必填 - 配置服务的调用者,用于对请求进行认证
global_auth bool 选填 - 若配置为true,则全局生效认证机制; 若配置为false,则只对做了配置的域名和路由生效认证机制; 若不配置则仅当没有域名和路由配置时全局生效(兼容机制)

consumers中每一项的配置字段说明如下:

名称 数据类型 填写要求 默认值 描述
name string 必填 - 配置该consumer的名称
jwks string 必填 - https://www.rfc-editor.org/rfc/rfc7517 指定的json格式字符串,是由验证JWT中签名的公钥(或对称密钥)组成的Json Web Key Set
issuer string 必填 - JWT的签发者,需要和payload中的iss字段保持一致
claims_to_headers array of object 选填 - 抽取JWT的payload中指定字段,设置到指定的请求头中转发给后端
from_headers array of object 选填 [{“name”:“Authorization”,“value_prefix”:"Bearer "}] 从指定的请求头中抽取JWT
from_params array of string 选填 access_token 从指定的URL参数中抽取JWT
from_cookies array of string 选填 - 从指定的cookie中抽取JWT
clock_skew_seconds number 选填 60 校验JWT的exp和iat字段时允许的时钟偏移量,单位为秒
keep_token bool 选填 true 转发给后端时是否保留JWT

注意:
只有当from_headers,from_params,from_cookies均未配置时,才会使用默认值

from_headers 中每一项的配置字段说明如下:

名称 数据类型 填写要求 默认值 描述
name string 必填 - 抽取JWT的请求header
value_prefix string 必填 - 对请求header的value去除此前缀,剩余部分作为JWT

claims_to_headers 中每一项的配置字段说明如下:

名称 数据类型 填写要求 默认值 描述
claim string 必填 - JWT
header string 必填 - 从payload取出字段的值设置到这个请求头中,转发给后端
override bool 选填 true true时,存在同名请求头会进行覆盖;false时,追加同名请求头

域名和路由级配置

名称 数据类型 填写要求 默认值 描述
allow array of string 必填 - 对于符合匹配条件的请求,配置允许访问的consumer名称

注意:

对于通过认证鉴权的请求,请求的header会被添加一个X-Mse-Consumer字段,用以标识调用者的名称。

配置示例

1、配置全局策略

在插件市场中找到JWT Auth进行策略配置。

consumers:
- issuer: "abcd"
  jwks: |
   {
    "keys": [
    {
       "kty": "RSA",
       "n": "u8SyxKf2kLkmOKOU-mcbXQmacQDCPtxfMGKzYx6HWaGcCFbIrFDubGIWhe3GRP5uQqXekqwDtiqurdGfUzOLSSLfe7bmCmEgntNbF9bgk8lZUhzszmb4sGk6VK4YiOiTWGYWn_7jyKyF_OXEpXY4C3WWWsZwQfLPNUYfVZE76o1MXT9F3622RhLSPOFVqJYL6RlzllvNc2PdfzVEBnFU4wKszT0n9J8ZrNAnlNUxOXi7Y78fLqQks60ERznZwytwB8krydQGkjH9y9pf70QFJW228mUxXHnPhG87Gi2eE62TardkBCvQcm4TJlEB5dnmhFYFhRkAR6IznUAjtkFZIw",
       "e": "AQAB",
       "use": "sig",
       "kid": "keyId",
       "alg": "RS256"
     }
    ]
   }
  name: "consumer1"
global_auth: false

2、配置路由级别

开启order-service微服务权限认证。

allow:
- "consumer1"

测试认证中心
1、生成用户登录token令牌

image-20231117140402178

2、测试token令牌

image-20231117140504500

Key 认证

在这里插入图片描述
功能说明
key-auth插件实现了基于 API Key 进行认证鉴权的功能,支持从 HTTP 请求的 URL 参数或者请求头解析 API Key,同时验证该 API Key 是否有权限访问。

配置字段
全局配置

名称 数据类型 填写要求 默认值 描述
consumers array of object 必填 - 配置服务的调用者,用于对请求进行认证
keys array of string 必填 - API Key 的来源字段名称,可以是 URL 参数或者 HTTP 请求头名称
in_query bool in_query 和 in_header 至少有一个为 true true 配置 true 时,网关会尝试从 URL 参数中解析 API Key
in_header bool in_query 和 in_header 至少有一个为 true true 配置 true 时,网关会尝试从 HTTP 请求头中解析 API Key
global_auth bool 选填 - 若配置为true,则全局生效认证机制; 若配置为false,则只对做了配置的域名和路由生效认证机制; 若不配置则仅当没有域名和路由配置时全局生效(兼容机制)

consumers中每一项的配置字段说明如下:

名称 数据类型 填写要求 默认值 描述
credential string 必填 - 配置该consumer的访问凭证
name string 必填 - 配置该consumer的名称

域名和路由级配置

名称 数据类型 填写要求 默认值 描述
allow array of string 必填 - 对于符合匹配条件的请求,配置允许访问的consumer名

注意:
对于通过认证鉴权的请求,请求的header会被添加一个X-Mse-Consumer字段,用以标识调用者的名称。

配置示例
1、对特定路由或域名开启

以下配置将对网关特定路由或域名开启 Key Auth 认证和鉴权,注意credential字段不能重复

全局配置

consumers:
- credential: 2bda943c-ba2b-11ec-ba07-00163e1250b5
  name: consumer1
- credential: c8c8e9ca-558e-4a2d-bb62-e700dcc40e35
  name: consumer2
keys:
- apikey
in_query: true
global_auth: false

路由级配置

对 route-a 和 route-b 这两个路由做如下配置:

allow: 
- consumer1
- ```
对 *.exmaple.com 和 test.com 在这两个域名做如下配置:
```yml
allow:
- consumer2

请求未提供 API Key,返回401

curl  http://xxx.hello.com/test

相关错误码

HTTP 状态码 出错信息 原因说明
401 No API key found in request 请求未提供 API Key
401 Request denied by Key Auth check. Invalid API key 不允许当前 API Key 访问
403 Request denied by Basic Auth check. Unauthorized consumer 请求的调用方无访问权限

请求屏蔽

在这里插入图片描述
功能说明
request-block插件实现了基于 URL、请求头等特征屏蔽 HTTP 请求,可以用于防护部分站点资源不对外部暴露。

配置字段

名称 数据类型 填写要求 默认值 描述
block_urls array of string 选填,block_urls,block_headers,block_bodies 中至少必填一项 - 配置用于匹配需要屏蔽 URL 的字符串
block_headers array of string 选填,block_urls,block_headers,block_bodies 中至少必填一项 - 配置用于匹配需要屏蔽请求 Header 的字符串
block_bodies array of string 选填,block_urls,block_headers,block_bodies 中至少必填一项 - 配置用于匹配需要屏蔽请求 Body 的字符串
blocked_code number 选填 403 配置请求被屏蔽时返回的 HTTP 状态码
blocked_message string 选填 - 配置请求被屏蔽时返回的 HTTP 应答 Body
case_sensitive bool 选填 true 配置匹配时是否区分大小写,默认区分

配置示例
1、屏蔽请求 url 路径

block_urls:
- swagger.html
- foo=bar
case_sensitive: false

根据该配置,下列请求将被禁止访问:

curl http://example.com?foo=Bar
curl http://exmaple.com/Swagger.html

2、屏蔽请求 header

block_headers:
- example-key
- example-value

根据该配置,下列请求将被禁止访问:

curl http://example.com -H 'example-key: 123'
curl http://exmaple.com -H 'my-header: example-value'

3、屏蔽请求 body

block_bodies:
- "hello world"
case_sensitive: false

根据该配置,下列请求将被禁止访问:

curl http://example.com -d 'Hello World'
curl http://exmaple.com -d 'hello world'

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力
在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到