【Nacos】 鉴权

Metadata

title: 【Nacos】 鉴权
date: 2023-01-03 21:28
tags:
  - 行动阶段/完成
  - 主题场景/组件
  - 笔记空间/KnowladgeSpace/ProgramSpace/ModuleSpace
  - 细化主题/Module/Nacos/插件
categories:
  - Nacos
keywords:
  - Nacos
description: 【Nacos】 鉴权

【Nacos】 鉴权

Nacos 从 2.1.0 版本开始,支持通过 SPI 的方式注入鉴权相关插件,并在application.properties配置文件中选择某一种插件实现作为实际鉴权服务。本文档会详细介绍如何实现一个鉴权插件和如何使其生效。

注意: 目前鉴权插件还处于 Beta 测试的阶段,其 API 及接口定义可能会随后续版本升级而有所修改,请注意您的插件适用版本。

鉴权插件中的概念

鉴权,通俗的表达就是,验证 是否能够对 某个东西 进行 某种操作 ,因此 Nacos 在设计鉴权插件时,将鉴权信息主要抽象为身份信息资源操作类型3 类主要概念。

身份信息 IdentityContext

身份信息 (IdentityContext) 是请求发起主体在 Nacos 鉴权插件中的抽象。由于不同的插件实现,身份信息可能不同,较为灵活;比如用户名和密码是一种身份信息,accessToken 又是另一种身份信息。因此身份信息 (IdentityContext) 并没有限制具体的个数和名字,插件实现可以自定义任意个数和身份关键字,Nacos 将会从请求中自动获取插件实现定义的身份关键字及其对应的值注入到身份信息 (IdentityContext) 中,供插件使用。

其中必定会包含的内容有:

字段名 描述
remote_ip 请求来源 ip

资源 Resource

资源 (Resource) 是请求所操作对象在 Nacos 鉴权插件中的抽象。它主要由 Nacos 来定义,具体可以是某个配置,某个服务,或者某个分组。

资源 (Resource) 主要由以下内容组成:

字段名 描述
namespaceId 请求资源的命名空间 ID,部分接口可能没有该值
group 请求资源的分组名,部分接口可能没有该值
name 请求资源的资源名,如服务名或配置的 dataId,部分接口可能是定义的特殊值,如nacos/admin
type 请求资源的类型,可能取值为SignType中的枚举值,主要表示该资源所相关的模块
properties 请求资源的扩展配置,不属于上述的资源相关信息,会被放如 properties 中,比如 Grpc 请求的 Request 名称或@Secured注解上的 tags 等

操作类型 Action

操作类型 (Action) 是请求操作在 Nacos 鉴权插件中的抽象,主要有读操作R和写操作W,详情查看ActionTypes枚举。

服务端插件

开发 Nacos 服务端鉴权插件,首先需要依赖鉴权插件的相关 API

        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-auth-plugin</artifactId>
            <version>${project.version}</version>
        </dependency>

${project.version} 为您开发插件所对应的 Nacos 版本

随后实现com.alibaba.nacos.plugin.auth.spi.server.AuthPluginService接口, 并将您的实现添加到 SPI 的 services 当中。

接口中需要实现的方法如下:

方法名 入参内容 返回内容 描述
getAuthServiceName void String 插件的名称,当名字相同时,后加载的插件会覆盖先加载的插件。
identityNames void Collection 插件的身份信息关键字,Nacos 会从请求中获取以这些关键字为 key 的参数,并注入到 IdentityContext 中。
enableAuth ActionTypes,SignType boolean 在调用validateIdentity和validateAuthority前调用,插件可自行判断是否对此类型的操作或此类型的模块进行鉴权。
validateIdentity IdentityContext, Resource boolean 对身份信息进行验证,在validateAuthority前调用
validateAuthority IdentityContext, Permission boolean 对权限进行验证,在validateIdentity返回为true时调用

加载服务端插件

插件开发完成后,需要打包成 jar/zip,放置到 nacos 服务端的 classpath 中,如果您不知道如何修改 classpath,请直接放置到${nacos-server.path}/plugins

放置后,需要修改${nacos-server.path}/conf/application.properties中的以下配置

### 所启用的Nacos的鉴权插件的名称,与`com.alibaba.nacos.plugin.auth.spi.server.AuthPluginService`的`getAuthServiceName`返回值对应
nacos.core.auth.system.type=${authServiceName}

### 开启鉴权功能
nacos.core.auth.enabled=true

随后重启 nacos 集群,在有请求访问到 nacos 节点后,可以从${nacos-server.path}/logs/nacos.log中看到如下日志:

[AuthPluginManager] Load AuthPluginService(xxxx) AuthServiceName(xxx) successfully.

使用 Nacos 自带的鉴权插件

Nacos 默认带有一个鉴权的简易实现,主要是为防止业务错用的弱鉴权体系,不是防止恶意攻击的强鉴权体系。开启和使用方式请查看文档[[【Nacos】 权限认证]] 用户指南 - 权限认证.

客户端插件

Nacos 的客户端鉴权插件主要工作为将鉴权相关的身份信息,注入到请求中,让每个请求都能够被对应的服务端鉴权插件识别。

在 Nacos 的 Java 客户端默认自带两个实现:

  • 使用usernamepasswordaccessToken的简易鉴权实现;
  • 使用accessKeysecretKey的阿里云鉴权实现;

Nacos 简易鉴权实现

当构造客户端实例时传入的 properties 中带有usernamepassword时,客户端会使用简易鉴权实现插件注入身份信息; 如:

Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR, "localhost:8848");
properties.setProperty(PropertyKeyConst.USERNAME, "nacos");
properties.setProperty(PropertyKeyConst.PASSWORD, "nacos");
NamingFactory.createNamingService(properties);
ConfigFactory.createConfigService(properties);

该插件会异步地通过usernamepassword进行登录,获取登录成功后的accessToken,并将accessToken注入到所有客户端请求中,开发者可以根据accessToken在实现的服务端插件中进行身份验证及后续的权限验证。

阿里云鉴权实现

当 properties 中带有accessKeysecretKey时,则会使用阿里云鉴权实现注入身份信息,如:

Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR, "localhost:8848");
properties.setProperty(PropertyKeyConst.ACCESS_KEY, "nacos");
properties.setProperty(PropertyKeyConst.SECRET_KEY, "nacos");
NamingFactory.createNamingService(properties);
ConfigFactory.createConfigService(properties);

该插件会根据accessKeysecretKey以及请求的资源内容,自动生成对应的请求签名,并注入到请求中,根据资源类型的不同,请求中的身份信息关键字可能不同:

类型 身份关键字 描述
NamingService ak accessKey
NamingService signature 注册中心模块的签名信息
NamingService data 签名数据,主要是时间戳
ConfigService Spas-AccessKey accessKey
ConfigService Spas-Signature 配置中心模块的签名信息
ConfigService Timestamp 请求的时间戳
ConfigService Spas-SecurityToken 临时 token(启用阿里云 STS 功能时使用)

开发者可以根据以上信息,在实现的服务端插件中进行身份验证及后续的权限验证。

其他自定义插件

考虑到开发者的鉴权插件可能有自定义的身份信息关键字,因此 Nacos 的 Java 客户端同样可以使用 SPI 方式注入对应的插件实现。

开发 Nacos 客户端鉴权插件,首先需要依赖鉴权插件的相关 API

        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-auth-plugin</artifactId>
            <version>${project.version}</version>
        </dependency>

${project.version} 为您开发插件所对应的 Nacos 版本

随后实现com.alibaba.nacos.plugin.auth.spi.client.ClientAuthService接口, 并将您的实现添加到 SPI 的 services 当中。

接口中需要实现的方法如下:

方法名 入参内容 返回内容 描述
setServerList List,Nacos 服务端地址列表 void 初始化时会调用此接口注入 Nacos 的服务列表,方便插件访问 nacos 服务端,如调用登录接口等
setNacosRestTemplate NacosRestTemplate,Nacos 的 http 客户端 void 初始化时会调用此接口注入 Nacos 的 http 客户端,方便插件访问 nacos 服务端,如调用登录接口等
login Properties,即初始化 Nacos 客户端时传入的参数 boolean 登录接口,主要执行的是身份信息的转换工作,如username,password转换为accessToken
getLoginIdentityContext Resource IdentityContext 获取经过登录接口转换后的身份信息,客户端会将该返回对象的内容全部注入到请求中

您也可以选择继承com.alibaba.nacos.plugin.auth.spi.client.AbstractClientAuthService,该父类默认实现了setServerListsetNacosRestTemplate

将开发完成的客户端插件打包成 jar/zip,放入到您应用的 classpath 中即可自动生效。

其他语言客户端鉴权插件

待社区贡献。