一、起因

 最近项目中需要对项目同时支持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. centos使用docker 安装 rabbitMq 消息队列

    1.拉取镜像 docker pull rabbitmq:3-management 如果出现报错: Get https://registry-1.docker.io/v2/: net/http: req ...

  2. Linux(centos)系统导出数据库文件命令

    mysqldump -uroot -p test > /test.sql -uroot 其中的root是数据库的用户名 test是要导出的数据库名字 test.sql 是要导出的数据库文件名字, ...

  3. Django网站实例效果

    Django是一种开源的大而且全的Web应用框架,是由python语言来编写的,优点十分明显: 功能完善.要素齐全:自带大量常用工具和框架(比如分页,auth,权限管理), 适合快速开发企业级网站. ...

  4. 【LeetCode】16. 3Sum Closest 最接近的三数之和

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 个人公众号:负雪明烛 本文关键词:3sum, three sum, 三数之和,题解,lee ...

  5. B. Arpa's weak amphitheater and Mehrdad's valuable Hoses

    B. Arpa's weak amphitheater and Mehrdad's valuable Hoses time limit per test 1 second memory limit p ...

  6. Parenthesis

      G - Parenthesis Time Limit:5000MS     Memory Limit:131072KB     64bit IO Format:%lld & %llu De ...

  7. World is Exploding(hdu5792)

    World is Exploding Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Other ...

  8. 第四十四个知识点:在ECC密码学方案中,描述一些基本的防御方法

    第四十四个知识点:在ECC密码学方案中,描述一些基本的防御方法 原文地址:http://bristolcrypto.blogspot.com/2015/08/52-things-number-44-d ...

  9. [Xavier] Understanding the difficulty of training deep feedforward neural networks

    目录 概 主要内容 Glorot X, Bengio Y. Understanding the difficulty of training deep feedforward neural netwo ...

  10. WEB文档在线预览解决方案

    web页面无法支持预览office文档,但是却可以预览PDF.flash文档,所以大多数解决方案都是在服务端将office文档转换为pdf,然后再通过js的pdf预览插件(谷歌浏览器等已经原生支持嵌入 ...