跳到主要内容
版本:2.2.0

认证

目前的认证体系使用的是SSO,对应的Nuget包是Aegis.Authorization.SSO,目前提供的版本是3.0.0-preview1 目前还提供ESS认证鉴权,对应的Nuget包是Aegis.Authorization.ESS

同时还需要引入Aegis.Core.Authorization,这个包提供了CurrentUserTokenHanlder等基本认证处理类。

启用认证和鉴权

Component.deps.json中的Services节点中确定包含了Authorization 注意此时只是开启了基础认证和鉴权,请确保引用认证和鉴权的实现组件,否则会报错。

现有 SSO认证&鉴权组件可供使用 如果确定要使用SsoAuthorize,请在Component.deps.json且中也包含它,且SsoAuthorize顺序应该在Authorization后面。

请确保在AppSettings或者加载的配置文件中包含SsoAuthorize节点的配置,具体如下:

"SSOAuthorize": {  
"Host": "http://10.11.13.75:30010/", //SSO 远程路径
"AppCode": "", //系统Code
"UserCode": "sys", //接口用户名
"Password": "App1234." //接口密码
},

如何获取当前用户

前端在请求接口的时候加入对应的HeaderAuthorization,并且传入具体的Token,表现为Bearer开头的Token Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJJU1MiOiJTU08iLCJTVUIiOiJwdWJsaWMiLCJJQVQiOiIxNjk0NTk4NjQ2IiwiRVhQIjoiMjAxMDI0NjY0NiIsIkpUSSI6ImUzYmJlMTVkLTk5NmUtNGM1Ni05MmZjLTA4NTU4Y2UxYzMwMSJ9.FILF7psfjlp61P9mDmrHH3ZlCj9AtsnY2dA1yhEAEPk

在传入Token后,只要该Token对应的用户确实已登录,后端就能通过CurrentUser.Value准确的获取到对应的登录用户。对应的数据结构如下

public class CustomeUser  
{
/// <summary>
/// 用户唯一标识
/// </summary>
public string UserIdentity { get; set; }

/// <summary>
/// 具体Token
/// </summary>
public string Token { get; set; }

/// <summary>
/// 过期时间
/// </summary>
public DateTime ExpireAt { get; set; }

/// <summary>
/// 自定义用户信息
/// </summary>
public object UserInfo { get; set; }
}

使用CurrentUser.Value.UserInfo就能获取到ISsoUserAdapter适配后的用户信息。也就是说这里的UserInfo实际上就是上面SsoUserAdapter.GetUser的返回值。

Aegis.Authorization.SSO中提供了扩展方法支持CurrentUser.Value.SsoUser()的方法来快速获取SsoUser用户实例。本质上是将CurrentUser.Value.UserInfo转换为SsoUserModel。所以只需要调用一次并存起来就行。

用户自定义字典

Aegis.Core.Authorization 为用户提供了额外信息存储的方式,方便业务系统存储用户的额外信息。用法如下,对应的value处存储的是object类型,注意在存储值类型的时候就会出现装箱拆箱的情况,请尽量传递引用类型进去。

CurrentUser.Value.Set("keyName",1); //设置内容,如果传值类型会触发装箱

var number = CurrentUser.Value.Get("keyName"); //获取内容

认证失败与过期机制

当使用[ApiAuthorize]标注Controller或者对应的控制器方法后,如果框架获取不到当前用户CurrentUser.Value获取不到数据的情况下,会返回Http状态码为401的错误信息,告知前端需要跳转登录页面。

使用[AllowAnonymous]标注即可在没有Token的情况下进入方法内,常用与登录和用户信息设置。

目前框架内的ApiControllerBase全都带上了[ApiAuthorize],之后会去掉。

目前的SSO没有过期机制,之后会接入过期与刷新。


ESS认证鉴权

启用ESS认证授权功能

appsettings.json 中添加 ESS 认证配置:

 "EssAuthorize": {
// ESS认证服务器地址
"DiscoveryUrl": "https://auth-sit.uicloud.com",
// ESS应用ID APPKey
"AppId": "DEZHENEMRTEST",
// ESS应用密钥 APPSecret
"AppSecret": "9855f3d80f8c5ad9256519b978a9a4d1b7a3c87464f3fa742caecf9f528033db",
// ESS开放服务的地址
"OpenUrl": "https://api-sit.uicloud.com/uap-portal-api",
// 扩展字段的key,当前只有JobNo(工号),多个以逗号分隔
"ExtendCodes": "JobNo"
}

在调试阶段可以关闭认证和授权,没有配置时默认关闭鉴权

  "Auth": {
"EnableAuthentication": true, // 是否启用认证校验
"EnableAuthorization": true // 是否启用授权校验
}

Component.deps.json文件中按顺序加入Authentication Authorization EssAuthorize

{
"Components": {
"Services": [
"Logging",
"Swagger",
"IdGenerator.SnowflakeId",
"BusinessServices",
"RequestValidation",
"EventBus",
"Jobs",
"Jobs.Postgres",
"SignalR",
"Authentication",
"Authorization",
"EssAuthorize"
],
"Middlewares": [
"Swagger",
"SignalR",
"Authentication",
"Authorization",
"EssAuthorize"
]
}
}

认证功能

采用redis存储用户会话信息,确保分布式环境下的用户认证一致性。 通过 ESS 认证服务器进行用户身份验证,支持 Token 的生成与刷新。

//获取Redis数据源
services.AddRedisSource<AegisRedisSource>(ConfigManager.Get<RedisOptions>("Redis"));
//注册ESS redis用户管理器
services.AddSingleton<IUserManager, EssRedisUserManager<AegisRedisSource>>();

登录login

提供登录接口/api/Auth/Login 根据前端传递的登录信息返回token,用户信息, 并缓存用户信息 实际的登录时前端在ESS提供的统一登录认证系统上进行登录获取授权码

// 前端传递的参数
{
// 从ESS获取的授权码
"userIdentity": "73c23ec90bf3f6deb775ecb8c3796b46",
// 登录成功跳转地址
"extendInfo": "http://localhost:4200"
}

// 具体实现在Login方法中
public Task<CustomUser> Login(LoginInfo loginInfo)

// 登录接口
curl --location --request POST 'http://localhost:5208/api/Auth/Login' \
--header 'Content-Type: application/json' \
--data-raw '{
"userIdentity": "9ef2200d4daa21283dfc85269ede7dd3",
"extendInfo": "http://localhost:4200"
}'

token校验CheckToken

当前所有的接口默认都需要token校验 添加[AllowAnonymous]不会进行校验

// 校验的header中的bear token
--header 'Authorization: Bearer eyJhbGciOi****
// 具体实现在CheckToken方法中
public Task<CustomUser?> CheckToken(string token)

UserInfo信息

 	/// <summary>
/// 用户姓名
/// </summary>
[JsonProperty("name")] public string Name { get; set; }

/// <summary>
/// AppId
/// </summary>
[JsonProperty("appId")] public string AppId { get; set; }

/// <summary>
/// 用户ID
/// </summary>
[JsonProperty("userId")] public string UserId { get; set; }

/// <summary>
/// 工号
/// </summary>
[JsonProperty("userCode")] public string UserCode { get; set; }

/// <summary>
/// 手机号
/// </summary>
[JsonProperty("userPhone")] public string UserPhone { get; set; }

登出logOut

提供登出的接口/api/Auth/Logout 这里的登出会清除用户信息的缓存,实际的登出是前端调用ESS的接口进行登出

// 具体实现在Logout方法中
public Task Logout(string token)

// 登出接口
curl --location --request POST 'http://localhost:5208/api/Auth/Logout' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI***' \
--data-raw '{}'

授权功能

默认的没有添加[AllowAnonymous]接口都是需要认证的接口 添加了[ApiAuthorize]的类或方法上 的接口表示不只是需要认证,还需要授权才能访问 用户token 访问与 客凭token访问均可以设置接口的是授权才能访问

DefaultResourcePermissionManager 中实现缓存接口的资源权限信息

// 缓存资源权限集合
public void SetResourcePermissions(IEnumerable<ResourcePermission> resourcePermissions, string key)
// 获取缓存中的资源权限集合, 缓存中没有则返回null,也可能是一个空集合
public IEnumerable<ResourcePermission> GetResourcePermissions(string key)

EssAuthorizationManager.cs 中实现了与ESS交互获取权限信息的逻辑

public Task<IEnumerable<ResourcePermission>> GetResourcePermissions(string token)

注解ApiAuthorize中会对当前访问的接口进行鉴权 其中会根据token来缓存权限信息20分钟,减少频繁访问ESS服务 不管是用户token(Header中的Authorization) 还是客凭token(Header中的ClientAuthorization) 都会走这个方法进行鉴权

public void OnAuthorization(AuthorizationFilterContext context)

客凭访问访问功能

A服务访问B服务 A服务需要携带客凭token访问B服务 A服务访问B服务,B服务需要校验客凭token 接口可以配置认证或者授权,会进行认证或鉴权

在启动项中需要注册

// 获取Redis数据源
services.AddRedisSource<AegisRedisSource>(ConfigManager.Get<RedisOptions>("Redis"));
// 注册ESS 获取客户端令牌管理器
services.AddSingleton<EssTokenManager<AegisRedisSource>>();

A服务访问前需要获取客凭token 在EssTokenManager.cs 中实现了获取客凭token的逻辑, 会缓存30分钟,减少频繁访问ESS服务

public string GetClientToken()

A服务中获取客凭token访问其他服务例子 客凭访问在header中携带ClientAuthorization 其中ClientAuthorization的值为通过EssTokenManager.GetClientToken()获取的客凭token

public interface IEssTestContract
{
[Get("/v1/message/getManualMsgDetail?id=1911308108789514242")]
public Task<string> GetManualMsgDetail([Header("ClientAuthorization")] string authorization);
}


public class AuthorizationEssClientTokenTestController : ApiControllerBase
{
private readonly IEssTestContract _essTestContract;
private readonly EssTokenManager<AegisRedisSource> _essTokenManager;

public AuthorizationEssClientTokenTestController(EssTokenManager<AegisRedisSource> essTokenManager)
{
var bo = new BrokerClient("https://mh-dev.uicloud.com/oe/mr/umr-app-store");
_essTestContract = bo.Get<IEssTestContract>();
_essTokenManager = essTokenManager;
}

public async Task<string> Test()
{
// 获取客户端令牌后调用接口的例子
var resut = _essTestContract.GetManualMsgDetail(_essTokenManager.GetClientToken()).Result;
return resut;
}

依赖关系

依赖 Aegis.Caching.Redis 用于用户会话和权限信息的缓存管理 依赖 Aegis.core.Authentication 和 Aegis.core.Authorization 提供基础的认证和授权框架支持

如何扩展

当前认证体系可以接入大量扩展,提供以下接口供扩展

接口名用途
IUserManagaer用户数据储存管理接口,当前认证后的用户的管理接口,比如默认就是存在内存里,之后还可以扩展存在Redis里、数据库里等
IAuthorizeManager具体认证管理接口,用于提供具体的认证流程,目前只提供了SSO的认证管理

开发模式快速验证

DEBUG模式下,可以使用简单Token来直接通过认证和鉴权,目前可以直接传入1来快速获取一个UserName为1的Fake用户。

DEBUG模式下依然支持使用正常用户查询,在RELEASE模式下只能通过正常鉴权。

版本支持需求:

  • Aegis.Core.Authorization > 2.0.2-preview1
  • Aegis.Authorization.SSO > 2.0.3