- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章在ASP.NET Core中实现一个Token base的身份认证实例由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
以前在web端的身份认证都是基于Cookie | Session的身份认证, 在没有更多的终端出现之前,这样做也没有什么问题,但在Web API时代,你所需要面对的就不止是浏览器了,还有各种客户端,这样就有了一个问题,这些客户端是不知道cookie是什么鬼的。 (cookie其实是浏览器搞出来的小猫腻,用来保持会话的,但HTTP本身是无状态的, 各种客户端能提供的无非也就是HTTP操作的API) 。
而基于Token的身份认证就是应对这种变化而生的,它更开放,安全性也更高.
基于Token的身份认证有很多种实现方式,但我们这里只使用微软提供的API.
接下来的例子将带领大家完成一个使用微软JwtSecurityTokenHandler完成一个基于beare token的身份认证.
注意:这种文章属于Step by step教程,跟着做才不至于看晕,下载完整代码分析代码结构才有意义.
前期准备 。
推荐使用VS2015 Update3作为你的IDE 。
你需要安装.NET Core的运行环境以及开发工具 。
创建项目 。
在VS中新建项目,项目类型选择ASP.NET Core Web Application(.NET Core), 输入项目名称为CSTokenBaseAuth 。
Coding 。
创建一些辅助类 。
在项目根目录下创建一个文件夹Auth,并添加RSAKeyHelper.cs以及TokenAuthOption.cs两个文件 。
在RSAKeyHelper.cs中 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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中 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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中添加如下代码:
1
2
3
4
5
6
|
services.AddAuthorization(auth =>
{
auth.AddPolicy(
"Bearer"
,
new
AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser().Build());
});
|
完整的代码应该是这样 。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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方法中添加如下代码 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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用的,比如当身份认证失败的时候会抛出异常,而这里就是处理这个异常的.
接下来在相同的方法中添加如下代码, 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
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();
});
});
|
应用JwtBearerAuthentication 。
1
2
3
4
5
6
7
8
9
10
|
app.UseJwtBearerAuthentication(
new
JwtBearerOptions {
TokenValidationParameters =
new
TokenValidationParameters {
IssuerSigningKey = TokenAuthOption.Key,
ValidAudience = TokenAuthOption.Audience,
ValidIssuer = TokenAuthOption.Issuer,
ValidateIssuerSigningKey =
true
,
ValidateLifetime =
true
,
ClockSkew = TimeSpan.FromMinutes(0)
}
});
|
完整的代码应该是这样 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
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。我们将在这里完成登录授权 。
在同文件下添加两个类,分别用来模拟用户模型,以及用户存储,代码应该是这样 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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<User> Users {
get
;
set
; } =
new
List<User> {
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中添加如下方法 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
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,接下来我们来添加另外一个方法来调用它 。
在相同文件中添加如下代码 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
[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"
});
}
}
|
该文件完整的代码应该是这样 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
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<User> Users {
get
;
set
; } =
new
List<User> {
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 。
在其中添加如下代码 。
1
2
3
4
5
6
7
8
|
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}"
;
}
|
为方法添加装饰属性 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
[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 。
其中的代码应该是这样 。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
using
Microsoft.AspNetCore.Mvc;
namespace
CSTokenBaseAuth.Controllers
{
[Route(
"[controller]/[action]"
)]
public
class
LoginController : Controller
{
public
IActionResult Index()
{
return
View();
}
}
}
|
在项目Views目录下新建一个名为Login的目录,并在其中新建一个Index.cshtml文件.
代码应该是这个样子 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
<html xmlns=
"http://www.w3.org/1999/xhtml"
>
<head>
<title></title>
</head>
<body>
<button id=
"getToken"
>getToken</button>
<button id=
"requestAPI"
>requestAPI</button>
<script src=
"https://code.jquery.com/jquery-3.1.1.min.js"
></script>
<script>
$(
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"
);
})
})
</script>
</body>
</html>
|
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.
原文链接:http://www.cnblogs.com/onecodeonescript/p/6061714.html 。
最后此篇关于在ASP.NET Core中实现一个Token base的身份认证实例的文章就讲到这里了,如果你想了解更多关于在ASP.NET Core中实现一个Token base的身份认证实例的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
如果我不定义自己的构造函数,Base *b = new Base; 与 Base *b = new Base(); 之间有什么区别吗? 最佳答案 初始化是标准中要遵循的一种 PITA...然而,这两个
是否有现成的函数可以在 C# 中进行基本转换?我希望将以 26 为基数和以 27 为基数的数字转换为以 10 为基数。我可以在纸上完成,但我不是一个非常有经验的程序员,如果可能的话,我宁愿不要从头开始
JNA 中'base'是什么意思 Pointer.getPointerArray(long base) Pointer.getStringArray(long base) ? JNA Document
我正在做一个将数字从 10 进制转换为 2 进制的基本程序。我得到了这段代码: #include #include #include #include using namespace std;
“假设以下代码: public class MultiplasHerancas { static GrandFather grandFather = new GrandFather();
当我分析算法的时候,我突然问自己这个问题,如果我们有三元计算机时间复杂度会更便宜吗?还是有任何基础可以让我们构建计算机,这样时间复杂度分析就无关紧要了?我在互联网上找不到太多,但是基于三元的计算机在给
一个简化的场景。三个类,GrandParent,Parent 和 Child。我想要做的是利用 GrandParent 和 Parent 构造函数来初始化一个 Child 实例。 class Gran
我编写了一个简单的函数来将基数为 10 的数字转换为二进制数。我编写的函数是我使用我所知道的简单工具的最佳尝试。我已经在这个网站上查找了如何执行此操作的其他方法,但我还不太了解它。我确定我编写的函数非
我尝试了以下代码将数字从 base-10 转换为另一个 base。如果目标基地中没有零(0),它就会工作。检查 79 和 3 并正确打印正确的 2221。现在尝试数字 19 和 3,结果将是 21 而
这个问题在这里已经有了答案: Is Big O(logn) log base e? (7 个答案) 关闭 8 年前。 Intro 练习 4.4.6 的大多数解决方案。算法第三版说,n*log3(n)
如何判断基类(B)的指针是否(多态)重写了基类的某个虚函数? class B{ public: int aField=0; virtual void f(){}; }; class C
我测试了这样的代码: class A { public A() { } public virtual void Test () { Console.WriteL
两者都采用相同的概念:定义一些行和列并将内容添加到特定位置。但是 Grid 是最常见的 WPF 布局容器,而 html 中基于表格的布局是 very controversial .那么,为什么 WPF
我试图在 JS 中“获得”继承。我刚刚发现了一种基本上可以将所有属性从一个对象复制到另一个对象的简洁方法: function Person(name){ this.name="Mr or Miss
class A { public override int GetHashCode() { return 1; } } class B : A { pu
我有一个 Base32 信息哈希。例如IXE2K3JMCPUZWTW3YQZZOIB5XD6KZIEQ ,我需要将其转换为base16。 我怎样才能用 PHP 做到这一点? 我的代码如下所示: $ha
我已经使用其实验界面对 Google Analytics 进行了一些实验,一切似乎都运行良好,但我无法找到 Google Analytics 属性如何达到变体目标的答案,即归因 session - 基
if (state is NoteInitial || state is NewNote) return ListView.builder(
MSVC、Clang 和 GCC 不同意此代码: struct Base { int x; }; struct Der1 : public Base {}; struct Der2 : public
我已经尝试构建一个 Base 10 到 Base 2 转换器... var baseTen = window.prompt("Put a number from Base 10 to conver
我是一名优秀的程序员,十分优秀!