一、起因

 最近项目中需要对项目同时支持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. 利用免费二维码API自动生成网址图片二维码

    调用第三方接口生成二维码 官方地址:http://goqr.me/api/ 示例 https://api.qrserver.com/v1/create-qr-code/?size=180x180&am ...

  2. C. Watching Fireworks is Fun(Codeforces 372C)

    C. Watching Fireworks is Fun time limit per test 4 seconds memory limit per test 256 megabytes input ...

  3. 【汇编语言】李忠《x86汇编语言——从实模式到保护模式》

    该书配套资料网址已经失效 配套资料和章节答案下载 查看最新作者网址:http://www.lizhongc.com/ 勘误表:https://wenku.baidu.com/view/9213288b ...

  4. .NET+Sqlite如何支持加密

    .NET+Sqlite如何支持加密 Sqlite SQLite 来源于公共领域 SQLite Is Public Domain. 确保代码不会受到任何专有或许可内容的污染,没有任何来自互联网上的未知来 ...

  5. Sufficient Statistic (充分统计量)

    目录 定义 充分统计量的判定 最小统计量 例子 Poisson Normal 指数分布 Gamma Sufficient statistic - Wikipedia Sufficient statis ...

  6. Java EE数据持久化框架笔记 • 【目录】

    章节 内容 实践练习 Java EE数据持久化框架作业目录(作业笔记) 第1章 Java EE数据持久化框架笔记 • [第1章 MyBatis入门] 第2章 Java EE数据持久化框架笔记 • [第 ...

  7. 编写Java程序,使用JTable表格组件展现人员信息列表

    返回本章节 返回作业目录 需求说明: 使用JTable组件显现人员信息列表 实现思路: 创建一个JTable对象. 创建一个JScrollPane对象(显示横向和纵向滚动条). 将表格添加到滚动面板. ...

  8. Ubuntu安装Rocksdb并调试

    前言 第一次写博客^_^ 系统是全新的Ubuntu20.04,什么都没有,一切从头开始安装 查看gcc和g++版本 sudo apt-get update gcc --version g++ --ve ...

  9. select 1 from 是什么意思?有什么作用?

    参考:https://www.douban.com/note/518373959/ 一.select 1 from 的作用1.select 1 from mytable 与 select anycol ...

  10. 自定义djangorestframework-simplejwt的验证表

    django restframework-simplejwt默认是通过调用django的get_user_model方法来得到验证表的表名,然后再通过查询id来验证是否有这个用户. 当需要自定义用户表 ...