一、起因

 最近项目中需要对项目同时支持JWT认证,以及自定义的认证校验方式认证。通过对官方文档了解,得到认证实现主要通过继承IAuthenticationHandler 或 AuthenticationHandler<TOptions>来实现自定义认证的处理。 

 那么接下来实现一个自定义的认证访问。

二、自定义认证实现

 1、根据前面内容得知,处理认证通过IAuthenticationHandler 实例处理;那么首先添加一个自定义IAuthenticationHandler 类型:

/// <summary>
/// 方式一:自定义认证处理器
/// </summary>
public class CustomerAuthenticationHandler : IAuthenticationHandler
{
private IUserService _userService;
public CustomerAuthenticationHandler(IUserService userService)
{
_userService = userService;
} /// <summary>
/// 自定义认证Scheme名称
/// </summary>
public const string CustomerSchemeName = "cusAuth"; private AuthenticationScheme _scheme;
private HttpContext _context; /// <summary>
/// 认证逻辑:认证校验主要逻辑
/// </summary>
/// <returns></returns>
public Task<AuthenticateResult> AuthenticateAsync()
{
AuthenticateResult result;
_context.Request.Headers.TryGetValue("Authorization", out StringValues values);
string valStr = values.ToString();
if (!string.IsNullOrWhiteSpace(valStr))
{
//认证模拟basic认证:cusAuth YWRtaW46YWRtaW4=
string[] authVal = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(valStr.Substring(CustomerSchemeName.Length + 1))).Split(':');
var loginInfo = new Dto.LoginDto() { Username = authVal[0], Password = authVal[1] };
var validVale = _userService.IsValid(loginInfo);
if (!validVale)
result = AuthenticateResult.Fail("未登陆");
else
{
var ticket = GetAuthTicket(loginInfo.Username, "admin");
result = AuthenticateResult.Success(ticket);
}
}
else
{
result = AuthenticateResult.Fail("未登陆");
}
return Task.FromResult(result);
} /// <summary>
/// 未登录时的处理
/// </summary>
/// <param name="properties"></param>
/// <returns></returns>
public Task ChallengeAsync(AuthenticationProperties properties)
{
_context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
return Task.CompletedTask;
} /// <summary>
/// 权限不足时处理
/// </summary>
/// <param name="properties"></param>
/// <returns></returns>
public Task ForbidAsync(AuthenticationProperties properties)
{
_context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
return Task.CompletedTask;
} /// <summary>
/// 初始化认证
/// </summary>
/// <param name="scheme"></param>
/// <param name="context"></param>
/// <returns></returns>
public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
{
_scheme = scheme;
_context = context;
return Task.CompletedTask;
} #region 认证校验逻辑 /// <summary>
/// 生成认证票据
/// </summary>
/// <param name="name"></param>
/// <param name="role"></param>
/// <returns></returns>
private AuthenticationTicket GetAuthTicket(string name, string role)
{
var claimsIdentity = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, name),
new Claim(ClaimTypes.Role, role),
}, CustomerSchemeName);
var principal = new ClaimsPrincipal(claimsIdentity);
return new AuthenticationTicket(principal, _scheme.Name);
} #endregion
} /// <summary>
/// 方式二:继承已实现的基类
/// </summary>
public class SubAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
public SubAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{
} protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
throw new NotImplementedException();
}
}

 2、在Startup.cs中启用自定义认证:

public void ConfigureServices(IServiceCollection services)
{
//other code
services.AddAuthentication(o =>
{
x.DefaultAuthenticateScheme = CustomerAuthenticationHandler.CustomerSchemeName;
x.DefaultChallengeScheme = CustomerAuthenticationHandler.CustomerSchemeName;
o.AddScheme<CustomerAuthenticationHandler>(CustomerAuthenticationHandler.CustomerSchemeName, CustomerAuthenticationHandler.CustomerSchemeName);
});
//other code
} public void Configure(IApplicationBuilder app)
{
//other code
app.UseRouting(); //在UseRouting后;UseEndpoints前添加以下代码
app.UseAuthentication();
app.UseAuthorization(); //other code
app.UseEndpoints()
}

 3、在控制器上添加认证标记,测试验证

//指定认证时,采用CustomerAuthenticationHandler.CustomerSchemeName
[Authorize(AuthenticationSchemes = CustomerAuthenticationHandler.CustomerSchemeName)]
[Route("api/[controller]")]
[ApiController]
public class AuditLogController : ControllerBase
{
//code
}

  调用

  

三、多认证支持

 在实际项目中可能存在,对一个控制器支持多种认证方式如:常用的Jwt认证、自定义认证等,那么如何实现呢?

 1、在Startup的ConfigureServices 方法中添加以下逻辑:

public void ConfigureServices(IServiceCollection services)
{
//other code
services.Configure<JwtSetting>(Configuration.GetSection("JWTSetting"));
var token = Configuration.GetSection("JWTSetting").Get<JwtSetting>();
//JWT认证
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
     //添加自定义认证处理器
x.AddScheme<CustomerAuthenticationHandler>(CustomerAuthenticationHandler.CustomerSchemeName, CustomerAuthenticationHandler.CustomerSchemeName);
}).AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(token.SecretKey)),
ValidIssuer = token.Issuer,
ValidAudience = token.Audience,
ValidateIssuer = false,
ValidateAudience = false
};
});
//other code
}

 2、在需要支持多种认证方式的控制器上添加标记:

//指定认证时,采用CustomerAuthenticationHandler.CustomerSchemeName
[Authorize(AuthenticationSchemes = CustomerAuthenticationHandler.CustomerSchemeName)]
[Route("api/[controller]")]
[ApiController]
public class AuditLogController : ControllerBase
{
//code
} //指定认证采用JWT
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class WeatherForecastController : ControllerBase
{
//code
}

  这样就支持了两种认证方式

 3、一个控制器支持多种认证类型:继承Jwt认证处理,并根据Scheme那么调用自定义的认证处理器:

/// <summary>
/// 方式二:同时支持多种认证方式
/// </summary>
public class MultAuthenticationHandler : JwtBearerHandler
{
public const string MultAuthName = "MultAuth";
IUserService _userService;
public MultAuthenticationHandler(IOptionsMonitor<JwtBearerOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IUserService userService)
: base(options, logger, encoder, clock)
{
_userService = userService;
} protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
Context.Request.Headers.TryGetValue("Authorization", out StringValues values);
string valStr = values.ToString();
if (valStr.StartsWith(CustomerAuthenticationHandler.CustomerSchemeName))
{
var result = Valid();
if (result != null)
return Task.FromResult(AuthenticateResult.Success(result));
else
return Task.FromResult(AuthenticateResult.Fail("未认证"));
}
else
return base.AuthenticateAsync();
} private AuthenticationTicket Valid()
{
Context.Request.Headers.TryGetValue("Authorization", out StringValues values);
string valStr = values.ToString();
if (!string.IsNullOrWhiteSpace(valStr))
{
//认证模拟basic认证:cusAuth YWRtaW46YWRtaW4=
string[] authVal = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(valStr.Substring(CustomerAuthenticationHandler.CustomerSchemeName.Length + 1))).Split(':');
var loginInfo = new Dto.LoginDto() { Username = authVal[0], Password = authVal[1] };
if (_userService.IsValid(loginInfo))
return GetAuthTicket(loginInfo.Username, "admin");
}
return null;
} /// <summary>
/// 生成认证票据
/// </summary>
/// <param name="name"></param>
/// <param name="role"></param>
/// <returns></returns>
private AuthenticationTicket GetAuthTicket(string name, string role)
{
var claimsIdentity = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, name),
new Claim(ClaimTypes.Role, role),
}, CustomerAuthenticationHandler.CustomerSchemeName);
var principal = new ClaimsPrincipal(claimsIdentity);
return new AuthenticationTicket(principal, CustomerAuthenticationHandler.CustomerSchemeName);
}
}

四、总结

 .Net Core中的自定义认证主要通过实现IAuthenticationHandler 接口实现,如果要实现多认证方式通过AddScheme 应用自定义实现的认证处理器。

 源码:github

 参考:认证

  

.Net Core中自定义认证实现的更多相关文章

  1. .NET Core中的认证管理解析

    .NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...

  2. [转].NET Core中的认证管理解析

    本文转自:http://www.cnblogs.com/durow/p/5783089.html 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用 ...

  3. 如何在ASP.NET Core中自定义Azure Storage File Provider

    文章标题:如何在ASP.NET Core中自定义Azure Storage File Provider 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p ...

  4. ASP.NET Core中自定义路由约束

    路由约束 ASP.NET Core中,通过定义路由模板,可以在Url上传递变量,同时可以针对变量提供默认值.可选和约束. 约束的使用方法是在属性路由上添加指定的约束名,用法如下: // 单个使用 [R ...

  5. CORE MVC 自定义认证

    微软的认证体系,集成了EF,和它的表结构,对于我们已有的系统,或者想高度自定义的人,该怎么办呢? 答案在: https://docs.microsoft.com/en-us/aspnet/core/s ...

  6. .net core 中的经典设计模式的应用

    .net core 中的经典设计模式的应用 Intro 前段时间我们介绍了23种设计模式,今天来分享一下 asp.net core 种我觉得比较典型的设计模式的应用 实例 责任链模式 asp.net ...

  7. asp.net core 2.1认证

    asp.net core 2.1认证 这篇文章基于asp.net core的CookieAuthenticationHandler来讲述. 认证和授权很相似,他们的英文也很相似,一个是Authenti ...

  8. asp.net Core 中AuthorizationHandler 实现自定义授权

    前言 ASP.NET Core 中 继承的是AuthorizationHandler ,而ASP.NET Framework 中继承的是AuthorizeAttribute. 它们都是用过重写里面的方 ...

  9. asp.net core 自定义认证方式--请求头认证

    asp.net core 自定义认证方式--请求头认证 Intro 最近开始真正的实践了一些网关的东西,最近写几篇文章分享一下我的实践以及遇到的问题. 本文主要介绍网关后面的服务如何进行认证. 解决思 ...

随机推荐

  1. 优雅的按键模块-----Multi-button

    优雅的按键模块-----Multi-button ​ 在我们日常开发和使用的过程中常常使用了一些按键,利用按键实现不同的功能,比如长按,短按,双击等等.但是每次都是采用标志等等来实现信息的读取,是否有 ...

  2. 【LeetCode】962. Maximum Width Ramp 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 单调栈 日期 题目地址:https://leetco ...

  3. 【LeetCode】922. Sort Array By Parity II 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 使用奇偶数组 排序 奇偶数位置变量 日期 题目地址: ...

  4. Codeforces A. Orchestra

    A. Orchestra time limit per test 2 seconds memory limit per test 256 megabytes input standard input ...

  5. python学习第三天:python基础(数据类型和变量)

    注释 以  # 开头的语句是注释,如,注释不会被编译运行: 格式 当语句以冒号:结尾时,缩进的语句视为代码块.按照约定俗成的管理,应该始终坚持使用4个空格的缩进(在文本编辑器中,需要设置把Tab自动转 ...

  6. Now冥想:崩溃服务和性能服务助力提升应用质量

    想就像心灵的"健身房",当遇到失眠或情绪问题时,我们可以通过冥想,抚平情绪波澜,享受放松时刻.<Now冥想>正是一款专注冥想与心理健康的应用.它基于国际先进的正念冥想理 ...

  7. 第二十六个知识点:描述NAF标量乘法算法

    第二十六个知识点:描述NAF标量乘法算法 NAF标量乘法算法是标量乘法算法的一种增强,该算法使用了非邻接形式(Non-Adjacent Form)表达,减少了算法的期望运行时间.下面是具体细节: 让\ ...

  8. IT6516DP转VGA转换器|替代台湾联阳IT6516方案|CS5212Capstone

    台湾联阳IT6516是一种高性能的DP显示端口到VGA转换器方案芯片.IT6516结合DisplayPort接收器和三重DAC,通过转换功能支持DisplayPort输入和VGA输出.内置Displa ...

  9. 简单的 Shell 脚本入门教程

    Shell脚本 运作方式与解释型语言相当,如果有语言基础,学起 Shell 脚本就非常容易,但是 Shell 与常见的语言不同,一些常见的函数在 Shell 中需要组合一些命令得以实现 工具推荐 Sh ...

  10. Ranger-Hdfs插件安装

    Ranger-Hdfs插件ranger-0.6.0-hdfs-plugin安装到Hdfs的所有NameNode节点, 其他的DataNode节点不需要安装. 1. 登陆hdfs安装的用户,hdfs/z ...