以前在web端的身份认证都是基于Cookie | Session的身份认证, 在没有更多的终端出现之前,这样做也没有什么问题,但在Web API时代,你所需要面对的就不止是浏览器了,还有各种客户端,这样就有了一个问题,这些客户端是不知道cookie是什么鬼的。 (cookie其实是浏览器搞出来的小猫腻,用来保持会话的,但HTTP本身是无状态的, 各种客户端能提供的无非也就是HTTP操作的API)

而基于Token的身份认证就是应对这种变化而生的,它更开放,安全性也更高。

基于Token的身份认证有很多种实现方式,但我们这里只使用微软提供的API。

接下来的例子将带领大家完成一个使用微软JwtSecurityTokenHandler完成一个基于beare token的身份认证。

注意:这种文章属于Step by step教程,跟着做才不至于看晕,下载完整代码分析代码结构才有意义。

创建项目

在VS中新建项目,项目类型选择ASP.NET Core Web Application(.NET Core), 输入项目名称为CSTokenBaseAuth

Coding

创建一些辅助类

在项目根目录下创建一个文件夹Auth,并添加RSAKeyHelper.cs以及TokenAuthOption.cs两个文件

在RSAKeyHelper.cs中using System.Security.Cryptography;

namespace CSTokenBaseAuth.Auth

{

public class RSAKeyHelper

{

public static RSAParameters GenerateKey()

{

using (var key = new RSACryptoServiceProvider(2048))

{

return key.ExportParameters(true);

}

}

}

}

在TokenAuthOption.cs中using System;

using Microsoft.IdentityModel.Tokens;

namespace CSTokenBaseAuth.Auth

{

public class TokenAuthOption

{

public static string Audience { get; } = "ExampleAudience";

public static string Issuer { get; } = "ExampleIssuer";

public static RsaSecurityKey Key { get; } = new RsaSecurityKey(RSAKeyHelper.GenerateKey());

public static SigningCredentials SigningCredentials { get; } = new SigningCredentials(Key, SecurityAlgorithms.RsaSha256Signature);

public static TimeSpan ExpiresSpan { get; } = TimeSpan.FromMinutes(20);

}

}

Startup.cs

在ConfigureServices中添加如下代码:services.AddAuthorization(auth =>

{

auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()

.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme‌)

.RequireAuthenticatedUser().Build());

});

完整的代码应该是这样public void ConfigureServices(IServiceCollection services)

{

// Add framework services.

services.AddApplicationInsightsTelemetry(Configuration);

// Enable the use of an [Authorize("Bearer")] attribute on methods and classes to protect.

services.AddAuthorization(auth =>

{

auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()

.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme‌)

.RequireAuthenticatedUser().Build());

});

services.AddMvc();

}

在Configure方法中添加如下代码app.UseExceptionHandler(appBuilder => {

appBuilder.Use(async (context, next) => {

var error = context.Features[typeof(IExceptionHandlerFeature)] as IExceptionHandlerFeature;

//when authorization has failed, should retrun a json message to client

if (error != null && error.Error is SecurityTokenExpiredException)

{

context.Response.StatusCode = 401;

context.Response.ContentType = "application/json";

await context.Response.WriteAsync(JsonConvert.SerializeObject(

new { authenticated = false, tokenExpired = true }

));

}

//when orther error, retrun a error message json to client

else if (error != null && error.Error != null)

{

context.Response.StatusCode = 500;

context.Response.ContentType = "application/json";

await context.Response.WriteAsync(JsonConvert.SerializeObject(

new { success = false, error = error.Error.Message }

));

}

//when no error, do next.

else await next();

});

});

这段代码主要是Handle Error用的,比如当身份认证失败的时候会抛出异常,而这里就是处理这个异常的。

接下来在相同的方法中添加如下代码,app.UseExceptionHandler(appBuilder => {

appBuilder.Use(async (context, next) => {

var error = context.Features[typeof(IExceptionHandlerFeature)] as IExceptionHandlerFeature;

//when authorization has failed, should retrun a json message to client

if (error != null && error.Error is SecurityTokenExpiredException)

{

context.Response.StatusCode = 401;

context.Response.ContentType = "application/json";

await context.Response.WriteAsync(JsonConvert.SerializeObject(

new { authenticated = false, tokenExpired = true }

));

}

//when orther error, retrun a error message json to client

else if (error != null && error.Error != null)

{

context.Response.StatusCode = 500;

context.Response.ContentType = "application/json";

await context.Response.WriteAsync(JsonConvert.SerializeObject(

new { success = false, error = error.Error.Message }

));

}

//when no error, do next.

else await next();

});

});

应用JwtBearerAuthenticationapp.UseJwtBearerAuthentication(new JwtBearerOptions {

TokenValidationParameters = new TokenValidationParameters {

IssuerSigningKey = TokenAuthOption.Key,

ValidAudience = TokenAuthOption.Audience,

ValidIssuer = TokenAuthOption.Issuer,

ValidateIssuerSigningKey = true,

ValidateLifetime = true,

ClockSkew = TimeSpan.FromMinutes(0)

}

});

完整的代码应该是这样using System;

using Microsoft.AspNetCore.Builder;

using Microsoft.AspNetCore.Hosting;

using Microsoft.Extensions.Configuration;

using Microsoft.Extensions.DependencyInjection;

using Microsoft.Extensions.Logging;

using Microsoft.AspNetCore.Authorization;

using Microsoft.AspNetCore.Authentication.JwtBearer;

using CSTokenBaseAuth.Auth;

using Microsoft.AspNetCore.Diagnostics;

using Microsoft.IdentityModel.Tokens;

using Microsoft.AspNetCore.Http;

using Newtonsoft.Json;

namespace CSTokenBaseAuth

{

public class Startup

{

public Startup(IHostingEnvironment env)

{

var builder = new ConfigurationBuilder()

.SetBasePath(env.ContentRootPath)

.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)

.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

if (env.IsEnvironment("Development"))

{

// This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.

builder.AddApplicationInsightsSettings(developerMode: true);

}

builder.AddEnvironmentVariables();

Configuration = builder.Build();

}

public IConfigurationRoot Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container

public void ConfigureServices(IServiceCollection services)

{

// Add framework services.

services.AddApplicationInsightsTelemetry(Configuration);

// Enable the use of an [Authorize("Bearer")] attribute on methods and classes to protect.

services.AddAuthorization(auth =>

{

auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()

.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme‌)

.RequireAuthenticatedUser().Build());

});

services.AddMvc();

}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)

{

loggerFactory.AddConsole(Configuration.GetSection("Logging"));

loggerFactory.AddDebug();

app.UseApplicationInsightsRequestTelemetry();

app.UseApplicationInsightsExceptionTelemetry();

#region Handle Exception

app.UseExceptionHandler(appBuilder => {

appBuilder.Use(async (context, next) => {

var error = context.Features[typeof(IExceptionHandlerFeature)] as IExceptionHandlerFeature;

//when authorization has failed, should retrun a json message to client

if (error != null && error.Error is SecurityTokenExpiredException)

{

context.Response.StatusCode = 401;

context.Response.ContentType = "application/json";

await context.Response.WriteAsync(JsonConvert.SerializeObject(

new { authenticated = false, tokenExpired = true }

));

}

//when orther error, retrun a error message json to client

else if (error != null && error.Error != null)

{

context.Response.StatusCode = 500;

context.Response.ContentType = "application/json";

await context.Response.WriteAsync(JsonConvert.SerializeObject(

new { success = false, error = error.Error.Message }

));

}

//when no error, do next.

else await next();

});

});

#endregion

#region UseJwtBearerAuthentication

app.UseJwtBearerAuthentication(new JwtBearerOptions {

TokenValidationParameters = new TokenValidationParameters {

IssuerSigningKey = TokenAuthOption.Key,

ValidAudience = TokenAuthOption.Audience,

ValidIssuer = TokenAuthOption.Issuer,

ValidateIssuerSigningKey = true,

ValidateLifetime = true,

ClockSkew = TimeSpan.FromMinutes(0)

}

});

#endregion

app.UseMvc(routes =>

{

routes.MapRoute(

name: "default",

template: "{controller=Login}/{action=Index}");

});

}

}

}

在Controllers中新建一个Web API Controller Class,命名为TokenAuthController.cs。我们将在这里完成登录授权

在同文件下添加两个类,分别用来模拟用户模型,以及用户存储,代码应该是这样public class User

{

public Guid ID { get; set; }

public string Username { get; set; }

public string Password { get; set; }

}

public static class UserStorage

{

public static List Users { get; set; } = new List {

new User {ID=Guid.NewGuid(),Username="user1",Password = "user1psd" },

new User {ID=Guid.NewGuid(),Username="user2",Password = "user2psd" },

new User {ID=Guid.NewGuid(),Username="user3",Password = "user3psd" }

};

}

接下来在TokenAuthController.cs中添加如下方法private string GenerateToken(User user, DateTime expires)

{

var handler = new JwtSecurityTokenHandler();

ClaimsIdentity identity = new ClaimsIdentity(

new GenericIdentity(user.Username, "TokenAuth"),

new[] {

new Claim("ID", user.ID.ToString())

}

);

var securityToken = handler.CreateToken(new SecurityTokenDescriptor

{

Issuer = TokenAuthOption.Issuer,

Audience = TokenAuthOption.Audience,

SigningCredentials = TokenAuthOption.SigningCredentials,

Subject = identity,

Expires = expires

});

return handler.WriteToken(securityToken);

}

该方法仅仅只是生成一个Auth Token,接下来我们来添加另外一个方法来调用它

在相同文件中添加如下代码[HttpPost]

public string GetAuthToken(User user)

{

var existUser = UserStorage.Users.FirstOrDefault(u => u.Username == user.Username && u.Password == user.Password);

if (existUser != null)

{

var requestAt = DateTime.Now;

var expiresIn = requestAt + TokenAuthOption.ExpiresSpan;

var token = GenerateToken(existUser, expiresIn);

return JsonConvert.SerializeObject(new {

stateCode = 1,

requertAt = requestAt,

expiresIn = TokenAuthOption.ExpiresSpan.TotalSeconds,

accessToken = token

});

}

else

{

return JsonConvert.SerializeObject(new { stateCode = -1, errors = "Username or password is invalid" });

}

}

该文件完整的代码应该是这样using System;

using System.Collections.Generic;

using System.Linq;

using System.Threading.Tasks;

using Microsoft.AspNetCore.Mvc;

using Newtonsoft.Json;

using System.IdentityModel.Tokens.Jwt;

using System.Security.Claims;

using System.Security.Principal;

using Microsoft.IdentityModel.Tokens;

using CSTokenBaseAuth.Auth;

namespace CSTokenBaseAuth.Controllers

{

[Route("api/[controller]")]

public class TokenAuthController : Controller

{

[HttpPost]

public string GetAuthToken(User user)

{

var existUser = UserStorage.Users.FirstOrDefault(u => u.Username == user.Username && u.Password == user.Password);

if (existUser != null)

{

var requestAt = DateTime.Now;

var expiresIn = requestAt + TokenAuthOption.ExpiresSpan;

var token = GenerateToken(existUser, expiresIn);

return JsonConvert.SerializeObject(new {

stateCode = 1,

requertAt = requestAt,

expiresIn = TokenAuthOption.ExpiresSpan.TotalSeconds,

accessToken = token

});

}

else

{

return JsonConvert.SerializeObject(new { stateCode = -1, errors = "Username or password is invalid" });

}

}

private string GenerateToken(User user, DateTime expires)

{

var handler = new JwtSecurityTokenHandler();

ClaimsIdentity identity = new ClaimsIdentity(

new GenericIdentity(user.Username, "TokenAuth"),

new[] {

new Claim("ID", user.ID.ToString())

}

);

var securityToken = handler.CreateToken(new SecurityTokenDescriptor

{

Issuer = TokenAuthOption.Issuer,

Audience = TokenAuthOption.Audience,

SigningCredentials = TokenAuthOption.SigningCredentials,

Subject = identity,

Expires = expires

});

return handler.WriteToken(securityToken);

}

}

public class User

{

public Guid ID { get; set; }

public string Username { get; set; }

public string Password { get; set; }

}

public static class UserStorage

{

public static List Users { get; set; } = new List {

new User {ID=Guid.NewGuid(),Username="user1",Password = "user1psd" },

new User {ID=Guid.NewGuid(),Username="user2",Password = "user2psd" },

new User {ID=Guid.NewGuid(),Username="user3",Password = "user3psd" }

};

}

}

接下来我们来完成授权验证部分

在Controllers中新建一个Web API Controller Class,命名为ValuesController.cs

在其中添加如下代码public string Get()

{

var claimsIdentity = User.Identity as ClaimsIdentity;

var id = claimsIdentity.Claims.FirstOrDefault(c => c.Type == "ID").Value;

return $"Hello! {HttpContext.User.Identity.Name}, your ID is:{id}";

}

为方法添加装饰属性[HttpGet]

[Authorize("Bearer")]

完整的文件代码应该是这样

using System.Linq;

using Microsoft.AspNetCore.Mvc;

using Microsoft.AspNetCore.Authorization;

using System.Security.Claims;

namespace CSTokenBaseAuth.Controllers

{

[Route("api/[controller]")]

public class ValuesController : Controller

{

[HttpGet]

[Authorize("Bearer")]

public string Get()

{

var claimsIdentity = User.Identity as ClaimsIdentity;

var id = claimsIdentity.Claims.FirstOrDefault(c => c.Type == "ID").Value;

return $"Hello! {HttpContext.User.Identity.Name}, your ID is:{id}";

}

}

}

最后让我们来添加视图

在Controllers中新建一个Web Controller Class,命名为LoginController.cs

其中的代码应该是这样using Microsoft.AspNetCore.Mvc;

namespace CSTokenBaseAuth.Controllers

{

[Route("[controller]/[action]")]

public class LoginController : Controller

{

public IActionResult Index()

{

return View();

}

}

}

在项目Views目录下新建一个名为Login的目录,并在其中新建一个Index.cshtml文件。

代码应该是这个样子

getToken

requestAPI

$(function () {

var accessToken = undefined;

$("#getToken").click(function () {

$.post(

"/api/TokenAuth",

{ Username: "user1", Password: "user1psd" },

function (data) {

console.log(data);

if (data.stateCode == 1)

{

accessToken = data.accessToken;

$.ajaxSetup({

headers: { "Authorization": "Bearer " + accessToken }

});

}

},

"json"

);

})

$("#requestAPI").click(function () {

$.get("/api/Values", {}, function (data) {

alert(data);

}, "text");

})

})

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持php中文网。

更多在ASP.NET Core中实现一个Token base的身份认证实例相关文章请关注PHP中文网!

本文原创发布php中文网,转载请注明出处,感谢您的尊重!

php 身份认证 claim,在ASP.NET Core中实现一个Token base的身份认证实例相关推荐

  1. 在ASP.NET Core中实现一个Token base的身份认证

    以前在web端的身份认证都是基于Cookie | Session的身份认证, 在没有更多的终端出现之前,这样做也没有什么问题, 但在Web API时代,你所需要面对的就不止是浏览器了,还有各种客户端, ...

  2. 在ASP.NET Core中使用Angular2,以及与Angular2的Token base身份认证

    Angular2是对Angular1的一次彻底的,破坏性的更新. 相对于Angular1.x,借用某果的广告语,唯一的不同,就是处处都不同. 首先,推荐的语言已经不再是Javascript,取而代之的 ...

  3. ASP.NET Core 中是否有 PostAsJsonAsync() 方法?

    咨询区 LP13 在 Asp.NET 中我一般都用 PostAsJsonAsync() 做数据提交,在 Asp.NET Core 时代我貌似没有找到,按照程序集的命名规范,我觉得应该也是由 Micro ...

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

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

  5. ASP.NET Core中使用表达式树创建URL

    当我们在ASP.NET Core中生成一个action的url会这样写: var url=_urlHelper.Action("Index", "Home"); ...

  6. ASP.NET Core中为指定类添加WebApi服务功能

    POCO Controller是 ASP.NET Core 中的一个特性,虽然在2015年刚发布的时候就有这个特性了,可是大多数开发者都只是按原有的方式去写,而没有用到这个特性.其实,如果利用这个特性 ...

  7. asp绑定gridview属性_如何在ASP.NET Core中自定义Azure Storage File Provider

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

  8. 如何简单的在 ASP.NET Core 中集成 JWT 认证?

    前情提要:ASP.NET Core 使用 JWT 搭建分布式无状态身份验证系统 文章超长预警(1万字以上),不想看全部实现过程的同学可以直接跳转到末尾查看成果或者一键安装相关的 nuget 包 自上一 ...

  9. Asp.Net Core 中IdentityServer4 实战之 Claim详解

    一.前言 由于疫情原因,让我开始了以博客的方式来学习和分享技术(持续分享的过程也是自己学习成长的过程),同时也让更多的初学者学习到相关知识,如果我的文章中有分析不到位的地方,还请大家多多指教:以后我会 ...

  10. asp.net core中使用cookie身份验证

    背景 ASP.NET Core Identity 是一个完整的全功能身份验证提供程序,用于创建和维护登录名. 但是, cookie 不能使用基于的身份验证提供程序 ASP.NET Core Ident ...

最新文章

  1. python 2x xlrd使用merged_cells 读取的合并单元格为空
  2. 搭建Git服务器教程转载
  3. 类加载过程中几个重点执行顺序整理
  4. 2021年春季学期-信号与系统-第六次作业参考答案-第十一小题
  5. 焦点轮播图——myfocus焦点图库
  6. 是什么会议_会议签到是什么,会议签到过程是怎样的?
  7. PHP架设网页微端,GeeM2引擎20180425版本搭建微端方法
  8. NFS rhel 7
  9. MVC---------ViewBag
  10. c语言视频教程全集(c语言视频教程 谭浩强)
  11. 你想要的宏基因组-微生物组知识全在这(2022.8)
  12. 许昌学院计算机系统试题,2016秋大学计算机(许昌学院)-中国大学mooc-题库零氪...
  13. 疫情下,嵌入式er该怎么进行职业规划,难点在哪?
  14. bme280(HAL库)
  15. 【代码片段分享】获取公历日期阴历日期二十四节气干支纪年传统节日Java版
  16. 爬虫出现Forbidden by robots.txt
  17. ACM Uva1594 Ducci序列
  18. java的class文件批量反编译
  19. GTD时间管理,如何收集?| 每天成就更大成功
  20. C++中volatile变量测试

热门文章

  1. 实体类转换为XML字符串
  2. 【职场攻略】比你的工资更重要的十件事
  3. IntelliJ IDEA如何去掉xml文件背景色
  4. 深入理解jQuery中的事件冒泡
  5. 南阳oj-----D的小L(algorithm全排列用法)
  6. pap认证失败_PPP 口令认证协议 (PAP) 的配置与故障排除
  7. 触摸屏调出虚拟键盘_苹果最新专利申请被曝光:“真实触感虚拟键盘”可能会用于ipad和笔记本电脑!...
  8. oracle多少条commit比较好,oracle什么时候须要commit
  9. 信用评分卡(python)
  10. 用Python 开发您的第一个 XGBoost 模型(收藏)