1 構(gòu)建IdentityServer4 服務(wù)

1.1 通過(guò)配置類(lèi)配置類(lèi)(Config)實(shí)例化IdentityServer4中間件
using IdentityServer4.Models;
namespace BuilderServer
{
///
/// 【配置--類(lèi)】
///
/// 摘要:
///??? 通過(guò)該中類(lèi)的方法成員,對(duì)過(guò)“IdentityServer4”中間件進(jìn)行配置設(shè)定,并根據(jù)這些配置設(shè)定。實(shí)例化“IdentityServer4”服務(wù)。
/// 說(shuō)明:
///???? 配置數(shù)據(jù)最好定義在“appsettings.json”文件中,而非直接嵌入定義在該配置類(lèi)。
///
///
public static class Config
{
///
/// 【獲取標(biāo)識(shí)資源數(shù)組】
///
/// 摘要:
///??? 獲取認(rèn)證用戶(hù)的多個(gè)證件單元(Claims:包含:如用戶(hù)ID、賬戶(hù)、電子郵件地址等)實(shí)例,并把這些實(shí)例存儲(chǔ)到數(shù)組實(shí)例中,為通過(guò)“IdentityServer4”中間件實(shí)現(xiàn)身份認(rèn)證服務(wù)提供數(shù)據(jù)支撐。
///
///
/// 返回:
///??? 數(shù)組實(shí)例,該數(shù)組實(shí)例中存儲(chǔ)著多個(gè)證件單元(Claims:包含:如用戶(hù)ID、賬戶(hù)、電子郵件地址等)實(shí)例。
///
///
public static IEnumerable
{
return new IdentityResource[]
{
???? new IdentityResources.OpenId(),
???? new IdentityResources.Profile(),
};
}
///
/// 【獲取作用數(shù)組】
///
/// 摘要:
///??? 獲取序中的Api控制器方法分類(lèi)實(shí)例,并把這些實(shí)例存儲(chǔ)到數(shù)組實(shí)例中,為通過(guò)“IdentityServer4”中間件實(shí)現(xiàn)身份認(rèn)證服務(wù)提供數(shù)據(jù)支撐。
/// 應(yīng)用場(chǎng)景:
///???? 在由于前端版本迭代,而需要更新Api控制器方法時(shí),為了兼容舊的前端就需要“Api版本”控制在不修改舊的Api控制器方法,而是定義新的Api控制器方法,來(lái)解決前端版本迭代的兼容性問(wèn)題。
///
///
/// 返回:
????///??? 數(shù)組實(shí)例,該數(shù)組實(shí)例中存儲(chǔ)著Api控制器方法分類(lèi)的多個(gè)實(shí)例。
///
///
public static IEnumerable GetApiScopeArray()
{
return new ApiScope[]
{
???? new ApiScope("api1"),
};
}
///
/// 【獲取客戶(hù)端數(shù)組】
///
/// 摘要:
///??? 通過(guò)“IdentityServer4”中間件,實(shí)例化多個(gè)客戶(hù)端實(shí)例(客戶(hù)端通過(guò)1個(gè)指定的客戶(hù)端實(shí)例獲取Token),并把實(shí)例存儲(chǔ)到數(shù)組實(shí)例中。
///
///
/// 返回:
///??? 數(shù)組實(shí)例,該數(shù)組實(shí)例中存儲(chǔ)著多個(gè)客戶(hù)端實(shí)例(客戶(hù)端通過(guò)1個(gè)指定的客戶(hù)端實(shí)例獲取Token)。
///
///
public static IEnumerable
{
return new Client[]
{
???? //客戶(hù)端以“client_credentials”方式獲取獲取Token。
???? new Client
???? {
???????? ClientId = "ClientCredential",
???????? ClientName = "客戶(hù)端憑證認(rèn)證",
???????? //grant_type:ClientCredential
??????????//Postman->Body->x-www-form-urlencoded參數(shù):
???????? //client_id:ClientCredential
???????? //client_secret:511536EF-F270-4058-80CA-1C89C192F69A
???????? //grant_type:client_credentials
???????? AllowedGrantTypes = GrantTypes.ClientCredentials,
???????? ClientSecrets = { new Secret("511536EF-F270-4058-80CA-1C89C192F69A".Sha256()) },
???????? AllowedScopes = { "api1" },
???????? AccessTokenLifetime = 120 //過(guò)期時(shí)間=2分鐘,默認(rèn)值:3600秒=1小時(shí)。
???? },
????? //客戶(hù)端以“password”方式獲取獲取Token。
???? new Client
???? {
???????? ClientId = "PasswordClient",
???????? ClientName = "客戶(hù)端密碼認(rèn)證",
???????? //grant_type:password
???????? //Postman->Body->x-www-form-urlencoded參數(shù):
???????? //client_id:PasswordClient
???????? //client_secret:511536EF-F270-4058-80CA-1C89C192F69A
???????? //grant_type:password
???????? //username:zz
???????? //password :123456,
???????? AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
???????? ClientSecrets = { new Secret("511536EF-F270-4058-80CA-1C89C192F69A".Sha256()) },
???????? AllowedScopes = { "api1" },
???????? AccessTokenLifetime = 120 //過(guò)期時(shí)間=2分鐘,默認(rèn)值3600秒=1小時(shí)。
???? },
? };
}
}
}
1.2 為“IdentityServer4”服務(wù)添加測(cè)試性用戶(hù)
using IdentityModel;
using IdentityServer4.Test;
using IdentityServer4;
using System.Security.Claims;
using System.Text.Json;
namespace BuilderServer
{
///
/// 【測(cè)試用戶(hù)--類(lèi)】
///
/// 摘要:
///??? 通過(guò)該類(lèi)中的方法成員,獲取測(cè)試用戶(hù)類(lèi)的多個(gè)實(shí)例,并把實(shí)例存儲(chǔ)到列表實(shí)例中,為測(cè)試指定用戶(hù)通過(guò)“IdentityServer4”服務(wù)獲取Token,測(cè)試性的用戶(hù)。
///
///
public class TestUsers
{
///
/// 【獲取客戶(hù)列表】
///
/// 摘要:
///??? 獲取測(cè)試用戶(hù)類(lèi)的多個(gè)實(shí)例,并把實(shí)例存儲(chǔ)到列表實(shí)例中,為測(cè)試指定用戶(hù)通過(guò)“IdentityServer4”服務(wù)獲取Token,測(cè)試性的用戶(hù)。
///
///
/// 返回:
///??? 列表實(shí)例,該列表實(shí)例中存儲(chǔ)著測(cè)試用戶(hù)類(lèi)的多個(gè)實(shí)例。
///
///
public static List
{
var address = new
{
???? street_address = "金水區(qū)",
???? locality = "鄭州",
???? postal_code = 69118,//郵編。
???? country = "中國(guó)"
};
//把測(cè)試用戶(hù)類(lèi)的多個(gè)實(shí)例存儲(chǔ)到列表實(shí)例中,為測(cè)試指定用戶(hù)通過(guò)“IdentityServer4”服務(wù)獲取Token,測(cè)試性的用戶(hù)。
return new List
{
???? new TestUser
???? {
???????? SubjectId = "1",
???????? Username = "zz",
???????? Password = "123456",
???????? //通過(guò)證件單元,構(gòu)建整個(gè)證件。
???????? Claims =
???????? {
???????????? new Claim(JwtClaimTypes.Name, "zz"),
???????????? new Claim(JwtClaimTypes.Email, "zz@email.com"),
???????????? new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean),
???????????? new Claim(JwtClaimTypes.Address, JsonSerializer.Serialize(address), IdentityServerConstants.ClaimValueTypes.Json)
???????? }
???? }
};
}
}
}
1.3 重構(gòu)Program類(lèi)
//通過(guò)配置類(lèi)中的數(shù)據(jù)實(shí)例,實(shí)例化過(guò)“IdentityServer4”中間件,最后把過(guò)“IdentityServer4”中間件依賴(lài)注入到內(nèi)置容器中,實(shí)現(xiàn)當(dāng)前程序據(jù)這些配置設(shè)定,實(shí)例化“IdentityServer4”服務(wù)。
builder.Services.AddIdentityServer()
?.AddTestUsers(TestUsers.GetUserList())//為“IdentityServer4”服務(wù)添加測(cè)試性用戶(hù)。
?.AddInMemoryIdentityResources(Config.GetIdentityResourceArray()) // 為“IdentityServer4”服務(wù)添加測(cè)試性用戶(hù)。
?.AddInMemoryApiScopes(Config.GetApiScopeArray())//指定客戶(hù)端所調(diào)用Api控件器方法的作用域(版本)
?.AddInMemoryClients(Config.GetClientArray())//1個(gè)指定的客戶(hù)端實(shí)例獲取Token的認(rèn)證方式。
?.AddDeveloperSigningCredential();//臨時(shí)生成的證書(shū)證書(shū)。
var app = builder.Build();
// 把“IdentityServer4”管道中間件集成到.Net7框架內(nèi)置管道中,以實(shí)現(xiàn)前程序?qū)Α癐dentityServer4”服務(wù)的支持。
app.UseIdentityServer();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
? app.UseSwagger();
? app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
//把內(nèi)置授權(quán)管道中間件集成到.Net7框架內(nèi)置管道中。
//注意:
//內(nèi)置授權(quán)管道中間件必須集成在“IdentityServer4”服務(wù)程序中,否則在使用Postman調(diào)試經(jīng)過(guò)認(rèn)證特性標(biāo)記的Api控制器方法時(shí)會(huì)出現(xiàn):“401Unauthorized”錯(cuò)誤。
app.UseAuthentication();
1.4 通過(guò)Postman測(cè)試IdentityServer4服務(wù)

2 通過(guò)“IdentityServer4.AccessTokenValidation”中間件獲取IdentityServer4服務(wù)所發(fā)送的“JwtBearer”令牌(Token)實(shí)例
2.1 TestController控制器
using IdentityModel.Client;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace AccessToken.Controllers
{
///
/// 【登錄管Api控制器--類(lèi)--無(wú)認(rèn)證特性標(biāo)記】
///
///
/// 摘要:
///???? 通過(guò)該類(lèi)中的方法成員,用于對(duì)IdentityServer4服務(wù)驗(yàn)證。
///
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
///
/// 【Swagger登錄--無(wú)認(rèn)證特性標(biāo)記】
///
///
/// 摘要:
///???? 獲取通過(guò)IdentityServer4服務(wù)所發(fā)送的“JwtBearer”令牌(Token)實(shí)例的字符串值。
///
///
/// 返回:
///??? 令牌(Token)實(shí)例的字符串值。
///
[HttpGet("GetToken")]
public async Task
{
//獲取IdentityServer4服務(wù)中的客戶(hù)端實(shí)例。
var client = new HttpClient();
var config = new DiscoveryDocumentRequest()
{
???? Address = "https://localhost:44360/",
???? Policy = new DiscoveryPolicy() { RequireHttps = false }
};? //忽略IP或域名時(shí)Https請(qǐng)求
var disco = await client.GetDiscoveryDocumentAsync(config);
//根據(jù)IdentityServer4服務(wù)中的客戶(hù)端實(shí)例,獲取“JwtBearer”令牌(Token)實(shí)例。
var tokenResponse = await client.RequestClientCredentialsTokenAsync(
???? new ClientCredentialsTokenRequest
???? {
???????? Address = disco.TokenEndpoint,
???????? ClientId = "ClientCredential",
???????? ClientSecret = "511536EF-F270-4058-80CA-1C89C192F69A",
???????? Scope = "api1",
???? });
if (tokenResponse.IsError)
????????{
???? return tokenResponse.Error;
}
//返回“JwtBearer”令牌(Token)實(shí)例的字符串值。
return tokenResponse.AccessToken;
}
///
/// 【Swagger登錄--有認(rèn)證特性標(biāo)記】
///
///
/// 摘要:
///??? 在通過(guò)IdentityServer4服務(wù)所發(fā)送的“JwtBearer”令牌(Token)實(shí)例認(rèn)證并授權(quán)后,獲取當(dāng)前Api方法的實(shí)例值。
///
///
/// 返回:
///??? 當(dāng)前Api方法的實(shí)例值。
///
[Authorize("api1")]
[HttpGet("GetValue")]
public IEnumerable
{
return new string[] { "value1", "value2" };
}
}
}
2.2 重構(gòu)Program類(lèi)
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System.Reflection;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
//通過(guò)“IdentityServer4.AccessTokenValidation”中間件,把“JwtBearer”中間件注入.Net7框架內(nèi)置容器中,
builder.Services.AddAuthentication("Bearer")
? .AddIdentityServerAuthentication(options =>
? {
? options.Authority = "https://localhost:44360/";//鑒權(quán)(認(rèn)證)服務(wù)地址
? options.RequireHttpsMetadata = false;
? //緩沖過(guò)期時(shí)間,“JwtBearer”令牌(Token)的總有效時(shí)間等于該時(shí)間加上jwt的過(guò)期時(shí)間,緩沖過(guò)期時(shí)間的默認(rèn)值為“5分鐘”,
? //當(dāng)前把緩沖過(guò)期時(shí)間設(shè)定為:0,指定令牌(Token)的總有效時(shí)間即為jwt的過(guò)期時(shí)間。
? //注意:
? //如果不設(shè)定“JwtBearer”緩沖過(guò)期時(shí)間設(shè)定為:0,即在IdentityServer4服務(wù)中的時(shí)間(120秒之后)過(guò)期后,經(jīng)過(guò)認(rèn)證特性標(biāo)記的Api控制器方法依然可以獲取其值,因?yàn)檫€“5分鐘”的緩沖過(guò)期。
? options.JwtValidationClockSkew = TimeSpan.FromSeconds(0);
? });
//通過(guò).Net7框架內(nèi)置認(rèn)證中間件,把"api1"策略注入.Net7框架內(nèi)置容器中,
builder.Services.AddAuthorization(option =>
{
? option.AddPolicy("Api1", builder =>
? {
? builder.RequireAuthenticatedUser();
? builder.RequireClaim("scope", "api1");
? });
});
//通過(guò)AddSwaggerGen依賴(lài)注入中間,獲取Api控制器方法的版本控制信息和注釋等數(shù)據(jù)信息,依賴(lài)注入.Net7框架的內(nèi)置容器中,為在“index.html”頁(yè)面上渲染顯示這些信息,作好預(yù)處理操作。
builder.Services.AddSwaggerGen(options =>
{
? options.SwaggerDoc("v1", new OpenApiInfo { Title = "IdentityServer4.AccessTokenValidation", Version = "v1" });
? //獲取"AccessToken.xml"文件的文件名。
? string _xmlFileName = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
? //獲取"SecondPracticeServer.xml"文件的絕對(duì)路徑。
? string _xmlFilePath = Path.Combine(AppContext.BaseDirectory, _xmlFileName);
? //把控件器行為方法中的注釋信息加載到"Swagger/index.html"頁(yè)面中的控件器行為方法進(jìn)行渲染顯示。
? options.IncludeXmlComments(_xmlFilePath, true);
});
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
2.3 通過(guò)Postman驗(yàn)證“IdentityServer4”服務(wù)及其授權(quán)
2.3.1 先通過(guò)Postman獲取“JwtBearer”令牌(Token)

2.3.2 通過(guò)Headers授權(quán)認(rèn)證特性標(biāo)記的Api控制器方法

2.3.3通過(guò)Authorization授權(quán)認(rèn)證特性標(biāo)記的Api控制器方法

3 通過(guò)“IdentityModel”中間件獲取IdentityServer4服務(wù)所發(fā)送的“JwtBearer”令牌(Token)實(shí)例
1、通過(guò)Nuget引用:IdentityModel包。
2、通過(guò)Nuget引用:Microsoft.AspNetCore.Authentication.JwtBearer包。
3.1 重構(gòu)Program類(lèi)
//通過(guò)“Microsoft.AspNetCore.Authentication.JwtBearer”中間件,把“JwtBearer”中間件注入.Net7框架內(nèi)置容器中,
builder.Services.AddAuthentication("Bearer")
? .AddJwtBearer("Bearer", options =>
? {
? options.Authority = "https://localhost:44360/";
? options.RequireHttpsMetadata = false;
? options.TokenValidationParameters = new TokenValidationParameters
? {
? //指示是否對(duì)指定令牌(Token)的過(guò)期時(shí)間進(jìn)行限定,當(dāng)前設(shè)定為:true,即限定。
? RequireExpirationTime = true,
? //指示是否對(duì)指定令牌(Token)的生命周期進(jìn)行自動(dòng)管理,當(dāng)前設(shè)定為:true,即管理,
? //當(dāng)前指定令牌(Token)的生命周期結(jié)束時(shí),程序必須重新生成1個(gè)新的指定令牌(Token)才能方法授權(quán)頁(yè)面。
? //使用當(dāng)前時(shí)間與Token的Claims中的NotBefore和Expires對(duì)比后,進(jìn)行管理。
? ValidateLifetime = true,
? //緩沖過(guò)期時(shí)間,“JwtBearer”令牌(Token)的總有效時(shí)間等于該時(shí)間加上jwt的過(guò)期時(shí)間,緩沖過(guò)期時(shí)間的默認(rèn)值為“5分鐘”,
? //當(dāng)前把緩沖過(guò)期時(shí)間設(shè)定為:0,指定令牌(Token)的總有效時(shí)間即為jwt的過(guò)期時(shí)間。
? //注意:
? //如果不設(shè)定“JwtBearer”緩沖過(guò)期時(shí)間設(shè)定為:0,即在IdentityServer4服務(wù)中的時(shí)間(120秒之后)過(guò)期后,經(jīng)過(guò)認(rèn)證特性標(biāo)記的Api控制器方法依然可以獲取其值,因?yàn)檫€“5分鐘”的緩沖過(guò)期。
? ClockSkew = TimeSpan.FromSeconds(0),
? };
? });
//通過(guò).Net7框架內(nèi)置認(rèn)證中間件,把"api1"策略注入.Net7框架內(nèi)置容器中,
builder.Services.AddAuthorization(option =>
{
? option.AddPolicy("Api1", builder =>
? {
? builder.RequireAuthenticatedUser();
? builder.RequireClaim("scope", "api1");
? });
});
//通過(guò)AddSwaggerGen依賴(lài)注入中間,獲取Api控制器方法的版本控制信息和注釋等數(shù)據(jù)信息,依賴(lài)注入.Net7框架的內(nèi)置容器中,為在“index.html”頁(yè)面上渲染顯示這些信息,作好預(yù)處理操作。
builder.Services.AddSwaggerGen(options =>
{
? options.SwaggerDoc("v1", new OpenApiInfo { Title = "IdentityServer4.AccessTokenValidation", Version = "v1" });
? //獲取"AccessToken.xml"文件的文件名。
? string _xmlFileName = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
? //獲取"SecondPracticeServer.xml"文件的絕對(duì)路徑。
? string _xmlFilePath = Path.Combine(AppContext.BaseDirectory, _xmlFileName);
? //把控件器行為方法中的注釋信息加載到"Swagger/index.html"頁(yè)面中的控件器行為方法進(jìn)行渲染顯示。
? options.IncludeXmlComments(_xmlFilePath, true);
});
3.2 通過(guò)Postman驗(yàn)證“IdentityServer4”服務(wù)及其授權(quán)
同上
4 注意:
4.1 啟動(dòng)
把所有項(xiàng)目的啟動(dòng)方式修改為:“IIS Express”
4.2 設(shè)定“JwtBearer”令牌(Token)緩沖過(guò)期時(shí)間為:0
4.2.1 通過(guò)“IdentityServer4.AccessTokenValidation”中間件設(shè)定
//通過(guò)“IdentityServer4.AccessTokenValidation”中間件,把“JwtBearer”中間件注入.Net7框架內(nèi)置容器中,
builder.Services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = "https://localhost:44360/";//鑒權(quán)(認(rèn)證)服務(wù)地址
options.RequireHttpsMetadata = false;
//緩沖過(guò)期時(shí)間,“JwtBearer”令牌(Token)的總有效時(shí)間等于該時(shí)間加上jwt的過(guò)期時(shí)間,緩沖過(guò)期時(shí)間的默認(rèn)值為“5分鐘”,
//當(dāng)前把緩沖過(guò)期時(shí)間設(shè)定為:0,指定令牌(Token)的總有效時(shí)間即為jwt的過(guò)期時(shí)間。
//注意:
//如果不設(shè)定“JwtBearer”緩沖過(guò)期時(shí)間設(shè)定為:0,即在IdentityServer4服務(wù)中的時(shí)間(120秒之后)過(guò)期后,經(jīng)過(guò)認(rèn)證特性標(biāo)記的Api控制器方法依然可以獲取其值,因?yàn)檫€“5分鐘”的緩沖過(guò)期。
options.JwtValidationClockSkew = TimeSpan.FromSeconds(0);
});
4.2.2 通過(guò)“Microsoft.AspNetCore.Authentication.JwtBearer”中間件設(shè)定
//通過(guò)“Microsoft.AspNetCore.Authentication.JwtBearer”中間件,把“JwtBearer”中間件注入.Net7框架內(nèi)置容器中,
builder.Services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://localhost:44360/";
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters
{
//指示是否對(duì)指定令牌(Token)的過(guò)期時(shí)間進(jìn)行限定,當(dāng)前設(shè)定為:true,即限定。
RequireExpirationTime = true,
//指示是否對(duì)指定令牌(Token)的生命周期進(jìn)行自動(dòng)管理,當(dāng)前設(shè)定為:true,即管理,
//當(dāng)前指定令牌(Token)的生命周期結(jié)束時(shí),程序必須重新生成1個(gè)新的指定令牌(Token)才能方法授權(quán)頁(yè)面。
//使用當(dāng)前時(shí)間與Token的Claims中的NotBefore和Expires對(duì)比后,進(jìn)行管理。
ValidateLifetime = true,
//緩沖過(guò)期時(shí)間,“JwtBearer”令牌(Token)的總有效時(shí)間等于該時(shí)間加上jwt的過(guò)期時(shí)間,緩沖過(guò)期時(shí)間的默認(rèn)值為“5分鐘”,
//當(dāng)前把緩沖過(guò)期時(shí)間設(shè)定為:0,指定令牌(Token)的總有效時(shí)間即為jwt的過(guò)期時(shí)間。
//注意:
//如果不設(shè)定“JwtBearer”緩沖過(guò)期時(shí)間設(shè)定為:0,即在IdentityServer4服務(wù)中的時(shí)間(120秒之后)過(guò)期后,經(jīng)過(guò)認(rèn)證特性標(biāo)記的Api控制器方法依然可以獲取其值,因?yàn)檫€“5分鐘”的緩沖過(guò)期。
ClockSkew = TimeSpan.FromSeconds(0),
};
});
4.3 內(nèi)置授權(quán)管道中間件必須集成在“IdentityServer4”服務(wù)程序中
內(nèi)置授權(quán)管道中間件必須集成在“IdentityServer4”服務(wù)項(xiàng)目中,否則在使用Postman調(diào)試經(jīng)過(guò)認(rèn)證特性標(biāo)記的Api控制器方法時(shí)會(huì)出現(xiàn):“401Unauthorized”錯(cuò)誤,如下圖所示。

對(duì)以上功能更為具體實(shí)現(xiàn)和注釋見(jiàn):221204_10IdentityServer4(初識(shí)IdentityServer4)。
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
本文題目:第11章初識(shí)IdentityServer4-創(chuàng)新互聯(lián)
瀏覽地址:http://www.yijiale78.com/article46/pcshg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)建站、Google、網(wǎng)站策劃、搜索引擎優(yōu)化、電子商務(wù)、網(wǎng)站改版
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容