.Net Core中自定义认证实现
一、起因
最近项目中需要对项目同时支持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中自定义认证实现的更多相关文章
- .NET Core中的认证管理解析
.NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...
- [转].NET Core中的认证管理解析
本文转自:http://www.cnblogs.com/durow/p/5783089.html 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用 ...
- 如何在ASP.NET Core中自定义Azure Storage File Provider
文章标题:如何在ASP.NET Core中自定义Azure Storage File Provider 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p ...
- ASP.NET Core中自定义路由约束
路由约束 ASP.NET Core中,通过定义路由模板,可以在Url上传递变量,同时可以针对变量提供默认值.可选和约束. 约束的使用方法是在属性路由上添加指定的约束名,用法如下: // 单个使用 [R ...
- CORE MVC 自定义认证
微软的认证体系,集成了EF,和它的表结构,对于我们已有的系统,或者想高度自定义的人,该怎么办呢? 答案在: https://docs.microsoft.com/en-us/aspnet/core/s ...
- .net core 中的经典设计模式的应用
.net core 中的经典设计模式的应用 Intro 前段时间我们介绍了23种设计模式,今天来分享一下 asp.net core 种我觉得比较典型的设计模式的应用 实例 责任链模式 asp.net ...
- asp.net core 2.1认证
asp.net core 2.1认证 这篇文章基于asp.net core的CookieAuthenticationHandler来讲述. 认证和授权很相似,他们的英文也很相似,一个是Authenti ...
- asp.net Core 中AuthorizationHandler 实现自定义授权
前言 ASP.NET Core 中 继承的是AuthorizationHandler ,而ASP.NET Framework 中继承的是AuthorizeAttribute. 它们都是用过重写里面的方 ...
- asp.net core 自定义认证方式--请求头认证
asp.net core 自定义认证方式--请求头认证 Intro 最近开始真正的实践了一些网关的东西,最近写几篇文章分享一下我的实践以及遇到的问题. 本文主要介绍网关后面的服务如何进行认证. 解决思 ...
随机推荐
- Miniconda入门教程
Miniconda 教程 介绍 Anaconda指的是一个开源的Python发行版本,其包含了conda.Python等180多个科学包及其依赖项.因为包含了大量的科学包,Anaconda 的下载文件 ...
- github源码下载总结
总结 下面来自我的经验,仅作参考. 下载时间选择 千万不要选择 晚上下载.下午7点后就不要从github上传或者下载代码,我用的是电信,踩坑: 这段时间后到第二天早上7点之前,这段时间内的上传和下载只 ...
- 【LeetCode】548. Split Array with Equal Sum 解题报告(C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 暴力 日期 题目地址:https://leetcode ...
- 【LeetCode】278. First Bad Version 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 解题方法 二分查找 日期 题目地址:https://leetcode.c ...
- Codeforces Round #358 (Div. 2) C. Alyona and the Tree
C. Alyona and the Tree time limit per test 1 second memory limit per test 256 megabytes input standa ...
- C++ 虚函数和友元
虚函数具有动态联编性,在类族中有强大功能:友元函数具有跨类访问的功能,本质却是一种对封装的破坏. 先看这样一个例子: #include<iostream> using namespace ...
- 关于 base64 编码
一.什么是Base64编码 Base64是一种用64个字符来表示任意二进制数据的方法.它是一种编码方式,而非加密方式.它通过将二进制数据转变为64个"可打印字符",完成了数据在HT ...
- Spring企业级程序设计 • 【第3章 面向切面编程】
全部章节 >>>> 本章目录 3.1 AOP基本概念和术语 3.1.1 AOP概念 3.1.2 AOP的术语解释 3.1.3 通知类型介绍 3.1.4 通过AOP模拟事务操 ...
- 很漂亮的一个背景控件——ribbons.js
写博客的人都喜欢优化自己的博客主页,博主也一样,找了一些背景控件,像canvas-nest.js等等,最终选择了ribbons.js,并基于源码,稍作了一丁点的修改,这里分享出来 (function ...
- centos6.5-rsync+inotify
一.目的 通过监控192.168.3.10的目录,实现实时同步. 实验环境 centos1 192.168.3.10 centos2 192.168.3.11 二.配置 cen ...