本文内容:
1、使用IdentityServer4搭建身份认证中心服务端;
2、不同客户端接入到身份认证中心实现身份认证;
话不多说,进入正题:
1、使用IdentityServer4搭建身份认证中心服务端;
a、使用nuget安装IdentityServer4,不做过多赘述
b、在Startup中注入IdentityServer4:
public void ConfigureServicesMain(IServiceCollection services)
{
//跨域
services.AddLevoxCors(new AddErpInjectOption());
//控制器
services.AddControllers();
//接口文档
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = $"身份认证中心 - {DateTime.Now:yyyy-MM-dd HH:mm:ss dddd}", Version = "v1" });
});
//身份认证
new IdentityServer4Service().Register(services);
}
IdentityServer4Service服务类:
public class IdentityServer4Service
{
/// <summary>
/// 将Id4注入到容器 CreateDate:2021-03-29 15:29:10.746 Author:Lingbug
/// </summary>
/// <param name="services"></param>
public void Register(IServiceCollection services)
{
//注入
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryIdentityResources(GetIdentityResources())
.AddInMemoryApiResources(GetApiResources())
.AddInMemoryApiScopes(GetApiScopes())
.AddInMemoryClients(FillClients(GetClients()))
//使用自定义认证逻辑(也就是登录逻辑)
.AddResourceOwnerValidator<ErpResourceOwnerPasswordValidator>();
}
/// <summary>
/// 获取可以访问的资源 LastUpdateDate:2021-04-15 17:08:33.402 Author:Lingbug
/// </summary>
/// <returns></returns>
private List<IdentityResource> GetIdentityResources() => new()
{
new IdentityResources.OpenId(),
new IdentityResources.Profile()
};
/// <summary>
/// 获取Api集合 CreateDate:2021-03-29 15:17:23.842 Author:Lingbug
/// </summary>
/// <returns></returns>
private List<ApiResource> GetApiResources()
{
return new()
{
new("ErpApi", "ERP接口")
{
Scopes = new List<string>() { "ErpApiScope" }
}
};
}
/// <summary>
/// 获取Scope集合 CreateDate:2021-03-29 15:17:59.323 Author:Lingbug
/// </summary>
/// <returns></returns>
private List<ApiScope> GetApiScopes()
{
return new()
{
new("ErpApiScope")
};
}
/// <summary>
/// 获取客户端集合(未做额外处理) CreateDate:2021-03-29 15:19:06.153 Author:Lingbug
/// </summary>
/// <returns></returns>
private List<Client> GetClients()
{
return new()
{
new()
{
ClientId = "ErpApi",
ClientSecrets = { new Secret("ErpApiSecret") },
AllowedScopes = new List<string>
{
"ErpApiScope",
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.OfflineAccess
}
}
};
}
/// <summary>
/// 额外处理客户端信息(加密,过期时间,授权类型等) CreateDate:2021-03-29 15:23:13.429 Author:Lingbug
/// </summary>
/// <param name="apiClients"></param>
/// <returns></returns>
private List<Client> FillClients(List<Client> apiClients)
{
//为空,不操作
if (apiClients.IsNullOrEmptyList()) return new List<Client>();
//读取配置
var tokenExpiredMinuteStr = ConfigurationUtil.GetString("TokenExpiredMinute");
//过期分钟
int tokenExpiredMinute = tokenExpiredMinuteStr.IsNullOrWhiteSpaceString()
? 60
: Convert.ToInt32(tokenExpiredMinuteStr);
//读取配置
var refreshTokenExpiredHoursStr = ConfigurationUtil.GetString("RefreshTokenExpiredHours");
//过期小时
int refreshTokenExpiredHours = tokenExpiredMinuteStr.IsNullOrWhiteSpaceString()
? 72
: Convert.ToInt32(refreshTokenExpiredHoursStr);
foreach (var apiClient in apiClients)
{
//加密
apiClient.ClientSecrets = apiClient.ClientSecrets.Select(r => new Secret(r.Value.Sha256())).ToList();
//密码模式
apiClient.AllowedGrantTypes = GrantTypes.ResourceOwnerPassword;
//token过期时间
apiClient.AccessTokenLifetime = tokenExpiredMinute * 60;
//配置token续签
ConfigRefreshToken(apiClient, refreshTokenExpiredHours);
}
//返回
return apiClients;
}
/// <summary>
/// 配置token续签 LastUpdateDate:2021-05-07 09:44:46.346 Author:Lingbug
/// </summary>
/// <param name="apiClient"></param>
/// <param name="refreshTokenExpiredHours"></param>
/// <returns></returns>
private Client ConfigRefreshToken(Client apiClient, int refreshTokenExpiredHours)
{
//开启token续签
apiClient.AllowOfflineAccess = true;
//绝对过期
apiClient.RefreshTokenExpiration = TokenExpiration.Absolute;
//续签token过期时间
apiClient.AbsoluteRefreshTokenLifetime = refreshTokenExpiredHours * 60 * 60;
//返回
return apiClient;
}
}
自定义认证逻辑(登录):
public class ErpResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
/// <summary>
/// 登录 LastUpdateDate:2021-03-30 10:00:01.398 Author:Lingbug
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
//登录操作
var loginResult = await GetLoginUserAsync(context);
if (loginResult.ErrorMsg.IsNullOrWhiteSpaceString())
{
//成功
context.Result = new GrantValidationResult(JsonConvert.SerializeObject(loginResult.User), OidcConstants.AuthenticationMethods.UserPresenceTest);
}
else
{
//失败
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, loginResult.ErrorMsg);
}
}
/// <summary>
/// 登录逻辑 LastUpdateDate:2021-04-12 11:29:56.632 Author:Lingbug
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
private async Task<(LoginUserDto User, string ErrorMsg)> GetLoginUserAsync(ResourceOwnerPasswordValidationContext context)
{
//sql
string sql = $@"select * from userInfo where username = '{context.UserName}' and password = '{context.Password}'";
//查询用户信息
LoginUserDto user = null;
//返回
return (user,null);
}
}
b、启用IdentityServer4身份认证:
public void ConfigureMain(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "身份认证中心 v1"));
app.UseRouting();
//跨域
app.UseCors(ErpInjectExtensions.GetLevoxCorsPolicyName());
app.UseHttpsRedirection();
//身份认证
app.UseIdentityServer();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
ok,身份认证中心(服务端)搭建完毕!
2、不同客户端接入到身份认证中心实现身份认证;
注入身份认证:
/// <summary>
/// 身份认证 LastUpdateDate:2021-03-30 09:49:51.414 Author:Lingbug
/// </summary>
public static class IdentityServer4AuthorizationExtensions
{
/// <summary>
/// 注入身份认证到容器(使用时,记得在Startup.cs->Configure方法->其中中间件app.UseAuthentication()(在app.UseAuthorization()上一行添加)) LastUpdateDate:2021-03-30 09:45:05.610 Author:Lingbug
/// </summary>
/// <param name="services"></param>
/// <param name="option"></param>
public static void AddErpAuthorization(this IServiceCollection services, AddErpInjectOption option)
{
//token类型
string tokenType = JwtBearerDefaults.AuthenticationScheme;
//身份认证中心地址
string serverUrl = GetIdentityServerUrl(option);
//是否使用https
bool isUseHttpsValidate = serverUrl.StartsWith("https://");
services.AddAuthentication(tokenType).AddJwtBearer(tokenType, options =>
{
//赋值
options.Authority = serverUrl;
//赋值
options.RequireHttpsMetadata = isUseHttpsValidate;
//赋值
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ClockSkew = TimeSpan.FromSeconds(5)
};
//options.Events = new JwtBearerEvents
//{
// OnMessageReceived = context =>
// {
// var accessToken = context.Request.Query["access_token"].ToString();
// var path = context.HttpContext.Request.Path.ToString();
// LoggerTestUtil.SimpleLog("OnMessageReceived", "accessToken:" + accessToken, "path:" + path);
// if (!string.IsNullOrEmpty(accessToken) && (path.StartsWith("/levox/testHub")))
// {
// context.Token = accessToken;
// }
// return Task.CompletedTask;
// }
//};
});
}
/// <summary>
/// 获取身份认证中心地址(如果没有传递,则读取配置LevoxFrameworkOption:AuthorizationCenterUrl) LastUpdateDate:2021-03-31 10:06:04.117 Author:Lingbug
/// </summary>
/// <param name="option"></param>
/// <returns></returns>
private static string GetIdentityServerUrl(AddErpInjectOption option)
{
//为空,读取配置
if (string.IsNullOrWhiteSpace(option.AuthorizationCenterUrl)) option.AuthorizationCenterUrl = ConfigurationUtil.GetString("AuthorizationCenterUrl");
//校验
if (option.AuthorizationCenterUrl.IsNullOrWhiteSpaceString()) throw new Exception("请配置身份认证地址!");
//记录日志
LoggerTestUtil.SimpleLog("身份认证地址为:" + option.AuthorizationCenterUrl);
//返回
return option.AuthorizationCenterUrl;
}
}
启用身份认证:
/// <summary>
/// 使用ERP中间件 LastUpdateDate:2021-04-01 09:55:50.710 Author:Lingbug
/// </summary>
/// <param name="app"></param>
/// <param name="env"></param>
/// <param name="option">配置信息</param>
public static void UseErpConfiguration(this IApplicationBuilder app, IWebHostEnvironment env, UseErpConfigurationOption option)
{
//错误页
app.UseDeveloperExceptionPage();
//静态资源
app.UseErpFileAccess(env, option);
//swagger
app.UseSwagger();
//swagger的json地址
if (option.SwaggerApiJsonUrl.IsNullOrWhiteSpaceString()) option.SwaggerApiJsonUrl = "/swagger/v1/swagger.json";
//swagger名称
if (option.SwaggerApiName.IsNullOrWhiteSpaceString()) option.SwaggerApiName = $"乐薇子系统Api - {DateTime.Now:yyyy-MM-dd HH:mm:ss}";
//使用
app.UseSwaggerUI(c => c.SwaggerEndpoint(option.SwaggerApiJsonUrl, option.SwaggerApiName));
//保存依赖注入
app.SaveContainer();
//路由
app.UseRouting();
//跨域
app.UseCors(ErpInjectExtensions.GetLevoxCorsPolicyName());
//https
app.UseHttpsRedirection();
//身份认证
app.UseAuthentication();
//授权
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
//注入集线器
endpoints.MapLevoxHubs();
//控制器
endpoints.MapControllers();
});
}
ok,接入完毕!
Ending~