使用JWT的ASP.NET CORE令牌身份验证和授权(无Cookie)——第1部分
目录
介绍
JWT(JSON Web令牌)
ASP.NET Core中的JWToken配置
用户模型类
创建令牌
第1步
第2步
第4步
令牌存储
中间件
自定义中间件app.Use()
中间件app.UseAuthentication()
自定义中间件代码
登录页面(Index.cshtml)
Home控制器
注销(Log Off)
登录演示项目
登录页面
LoginDemo.sln
第2部分
- 下载演示项目-1.9 MB
介绍
本文演示如何在ASP.NET CORE中使用JWT(JSON Web令牌)实现令牌身份验证和授权。本文中使用的方法不使用任何客户端cookie进行身份验证和授权。这意味着,令牌没有存储在客户端浏览器中,它是完全从服务器端处理的。由于本文主要侧重于实现ASP.NET CORE身份验证和授权,因此我们不会深入研究令牌配置和令牌创建。从实现的角度来看,仅简要介绍了令牌配置和创建。有很多文章详细解释了它。本文包含完整的代码和LoginDemo.sln项目。
在进入本主题之前,让我们简要介绍一下身份验证和授权。
身份验证:授予用户访问/许可以进入应用程序的权限。就像给人访问/许可进入建筑物的权限。
授权:这是在身份验证之后进行的。仅向用户授予应用程序某些页面的权限。这就像谁有权访问/许可进入10层楼的人,只能去2 或4 楼。
JWT(JSON Web令牌)
就像说的那样,JWToken是JSON格式的字符串值。为每个有效用户发出JWToken(身份验证)。在用户登录期间,令牌仅创建一次。用户将在随后的所有HTTP授权请求中使用该令牌,直到该用户从应用程序注销为止。
ASP.NET Core中的JWToken配置
我们不会涉及JWToken配置的每个细节。有很多文章对此进行了解释。使用 Microsoft.AspNetCore.Authentication.JwtBearer和Microsoft.IdentityModel.Tokens配置JWT。这是在Startup.cs中的 ConfigurationServices()方法中完成的。
您可以在下面的代码中看到,有两个部分令牌配置,services.AddAuthentication()和AddJwtBearer()。
services.AddAuthentication():此部分用于配置我们将要使用的身份验证方案或机制。在这里,我们告诉ASP.NET Core使用JWT承载令牌身份验证。这非常重要,因为这将在Configure()以后的方法中使用。
AddJwtBearer():在本部分中,我们使用密钥,到期日期,使用者等配置Token。密钥用于加密和解密令牌。创建令牌时应使用相同的密钥,我们将在“创建令牌”主题中看到。
public void ConfigureServices(IServiceCollection services)
{services.AddSession(options => {options.IdleTimeout = TimeSpan.FromMinutes(60);});services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);//Provide a secret key to Encrypt and Decrypt the Tokenvar SecretKey = Encoding.ASCII.GetBytes("YourKey-2374-OFFKDI940NG7:56753253-tyuw-5769-0921-kfirox29zoxv");//Configure JWT Token Authenticationservices.AddAuthentication(auth =>{auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;}).AddJwtBearer(token =>{token.RequireHttpsMetadata = false;token.SaveToken = true;token.TokenValidationParameters = new TokenValidationParameters{ValidateIssuerSigningKey = true,//Same Secret key will be used while creating the tokenIssuerSigningKey = new SymmetricSecurityKey(SecretKey),ValidateIssuer = true,//Usually, this is your application base URLValidIssuer = "http://localhost:45092/",ValidateAudience = true,//Here, we are creating and using JWT within the same application.//In this case, base URL is fine.//If the JWT is created using a web service, then this would be the consumer URL.ValidAudience = "http://localhost:45092/",RequireExpirationTime = true,ValidateLifetime = true,ClockSkew = TimeSpan.Zero};});
}
用户模型类
我们需要一个模型类供用户登录。使用用户ID,密码和其他凭据为User创建一个模型类。在“Models”文件夹下创建一个类User.cs。
public class User
{public string USERID { get; set; }public string PASSWORD { get; set; }public string FIRST_NAME { get; set; }public string LAST_NAME { get; set; }public string EMAILID { get; set; }public string PHONE { get; set; }public string ACCESS_LEVEL { get; set; }public string READ_ONLY { get; set; }
}
创建令牌
第1步
让我们创建一个TokenProvider.cs类,它将为用户创建/生成令牌。令牌仅创建一次,并在所有后续请求中使用,直到用户注销。在解决方案的根文件夹下,创建一个TokenProvider.cs类。
第2步
在创建Token之前,我们需要从登录页面获取UserID,并检查用户是否存在于我们的数据库中。出于演示目的,用户列表是存储在列表中的硬编码值。在现实世界中,这可能来自数据库或某些数据源。让我们向TokenProvider.cs类添加一个属性(UserList)。此属性是我们的用户数据存储区,几乎没有硬编码值。
//Using hard coded collection list as Data Store for demo purposes
//In reality, User data comes from Database or other Data Source.
private List UserList = new List
{new User { USERID = "jsmith@email.com", PASSWORD = "test", EMAILID = "jsmith@email.com", FIRST_NAME = "John", LAST_NAME = "Smith", PHONE = "356-735-2748", ACCESS_LEVEL = "Director", READ_ONLY = "true" },new User { USERID = "srob@email.com", PASSWORD = "test", FIRST_NAME = "Steve", LAST_NAME = "Rob", EMAILID = "srob@email.com", PHONE = "567-479-8537", ACCESS_LEVEL = "Supervisor", READ_ONLY = "false" },new User { USERID = "dwill@email.com", PASSWORD = "test", FIRST_NAME = "DJ", LAST_NAME = "Will", EMAILID = "dwill@email.com", PHONE = "599-306-6010", ACCESS_LEVEL = "Analyst", READ_ONLY = "false" },new User { USERID = "JBlack@email.com", PASSWORD = "test", FIRST_NAME = "Joe", LAST_NAME = "Black", EMAILID = "JBlack@email.com", PHONE = "764-460-8610", ACCESS_LEVEL = "Analyst", READ_ONLY = "true" }
};
第3步
我们需要在令牌中为应用程序设置用户权限(授权)。在令牌中,我们需要说明用户可以具有的权限级别。用户权限创建为Claims。创建令牌时,我们将在Claims对象集合中设置用户权限,并将其分配给Token。这些Claims值将用于在控制器中授予权限/授权用户。在MVC控制器的操作方法中,我们将使用“ACCESS_LEVEL”和“READ_ONLY”声明来设置用户权限。出于演示目的,对用户声明进行了硬编码。在这里,您可以连接到数据库并获得用户许可。
让我们添加一个方法(GetUserClaims())以获取用户权限级别并在TokenProvider.cs类中构建声明对象集合。
//Using hard coded values in claims collection list as Data Store for demo.
//In reality, User data comes from Database or other Data Source.
private IEnumerable GetUserClaims(User user)
{IEnumerable claims = new Claim[]{new Claim(ClaimTypes.Name, user.FIRST_NAME + " " + user.LAST_NAME),new Claim("USERID", user.USERID),new Claim("EMAILID", user.EMAILID),new Claim("PHONE", user.PHONE),new Claim("ACCESS_LEVEL", user.ACCESS_LEVEL.ToUpper()),new Claim("READ_ONLY", user.READ_ONLY.ToUpper())};return claims;
}
第4步
现在是时候为用户创建令牌了。首先,从登录页面获取用户ID,并检查用户是否在上面声明的UserList集合属性中。如果用户ID在列表中,则我们有一个注册用户。如果不是,则认证失败。不要发行令牌。
其次,从登录页面获取密码,然后检查密码是否与UserList中的密码匹配。如果是,则为用户创建一个令牌。如果不是,则认证失败,并且不创建/发行令牌。
要创建JWToken,我们将使用两个名称空间System.IdentityModel.Tokens.Jwt和Microsoft.IdentityModel.Tokens。让我们使用JwtSecurityToken()类创建令牌(此处,我不介绍令牌创建的详细信息。有很多文章介绍了JWT令牌创建)。在创建令牌时,用户声明值将加载到令牌“claims”属性中。我们正在调用上面的函数GetUserClaims(),该函数为用户加载声明。Token在采用UserID和Password作为输入的LoginUser()方法中创建。
让我们创建一个函数LoginUser(),其将TokenProvider.cs中的UserID和Password作为输入参数。
public string LoginUser(string UserID, string Password)
{//Get user details for the user who is trying to loginvar user = UserList.SingleOrDefault(x => x.USERID == UserID);//Authenticate User, Check if it’s a registered user in Databaseif (user == null)return null;//If it's registered user, check user password stored in Database //For demo, password is not hashed. Simple string comparison //In real, password would be hashed and stored in DB. Before comparing, hash the passwordif (Password == user.PASSWORD){ //Authentication successful, Issue Token with user credentials//Provide the security key which was given in the JWToken configuration in Startup.csvar key = Encoding.ASCII.GetBytes("YourKey-2374-OFFKDI940NG7:56753253-tyuw-5769-0921-kfirox29zoxv"); //Generate Token for user var JWToken = new JwtSecurityToken(issuer: "http://localhost:45092/",audience: "http://localhost:45092/",claims: GetUserClaims(user),notBefore: new DateTimeOffset(DateTime.Now).DateTime,expires: new DateTimeOffset(DateTime.Now.AddDays(1)).DateTime,//Using HS256 Algorithm to encrypt TokensigningCredentials: new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature));var token = new JwtSecurityTokenHandler().WriteToken(JWToken);return token;}else{return null;}
}
几点要考虑...
创建令牌时,我们需要提供与Startup.cs中JWToken配置的安全密钥相同的安全密钥。
var key = Encoding.ASCII.GetBytes("YourKey-2374-OFFKDI940NG7:56753253-tyuw-5769-0921-kfirox29zoxv");
“issuer”和“audience”应与在ConfigureServices()方法的Startup.cs中配置的值相同。
最后,TokenProvider.cs类如下所示:
using LoginDemo.Models;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;namespace LoginDemo
{public class TokenProvider{public string LoginUser(string UserID, string Password){//Get user details for the user who is trying to loginvar user = UserList.SingleOrDefault(x => x.USERID == UserID);//Authenticate User, Check if it’s a registered user in Database if (user == null)return null;//If it is registered user, check user password stored in Database//For demo, password is not hashed. It is just a string comparision //In reality, password would be hashed and stored in Database. //Before comparing, hash the password again.if (Password == user.PASSWORD){//Authentication successful, Issue Token with user credentials //Provide the security key which is given in //Startup.cs ConfigureServices() method var key = Encoding.ASCII.GetBytes("YourKey-2374-OFFKDI940NG7:56753253-tyuw-5769-0921-kfirox29zoxv"); //Generate Token for user var JWToken = new JwtSecurityToken( issuer: "http://localhost:45092/",audience: "http://localhost:45092/",claims: GetUserClaims(user),notBefore: new DateTimeOffset(DateTime.Now).DateTime,expires: new DateTimeOffset(DateTime.Now.AddDays(1)).DateTime,//Using HS256 Algorithm to encrypt Token signingCredentials: new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature));var token = new JwtSecurityTokenHandler().WriteToken(JWToken);return token;}else{return null;}}//Using hard coded collection list as Data Store for demo. //In reality, User details would come from Database.private List UserList = new List{new User { USERID = "jsmith@email.com", PASSWORD = "test", EMAILID = "jsmith@email.com", FIRST_NAME = "John", LAST_NAME = "Smith", PHONE = "356-735-2748", ACCESS_LEVEL = "Director", READ_ONLY = "true" },new User { USERID = "srob@email.com", PASSWORD = "test", FIRST_NAME = "Steve", LAST_NAME = "Rob", EMAILID = "srob@email.com", PHONE = "567-479-8537", ACCESS_LEVEL = "Supervisor", READ_ONLY = "false" },new User { USERID = "dwill@email.com", PASSWORD = "test", FIRST_NAME = "DJ", LAST_NAME = "Will", EMAILID = "dwill@email.com", PHONE = "599-306-6010", ACCESS_LEVEL = "Analyst", READ_ONLY = "false" },new User { USERID = "JBlack@email.com", PASSWORD = "test", FIRST_NAME = "Joe", LAST_NAME = "Black", EMAILID = "JBlack@email.com", PHONE = "764-460-8610", ACCESS_LEVEL = "Analyst", READ_ONLY = "true" }};//Using hard coded collection list as Data Store for demo. //In reality, User data comes from Database or other Data Source private IEnumerable GetUserClaims(User user){IEnumerable claims = new Claim[]{new Claim(ClaimTypes.Name, user.FIRST_NAME + " " + user.LAST_NAME),new Claim("USERID", user.USERID),new Claim("EMAILID", user.EMAILID),new Claim("PHONE", user.PHONE),new Claim("ACCESS_LEVEL", user.ACCESS_LEVEL.ToUpper()),new Claim("READ_ONLY", user.READ_ONLY.ToUpper())};return claims;}}
}
令牌存储
现在,我们已经验证了用户身份并为该用户颁发了令牌,我们需要将该令牌存储在某个位置,直到用户从应用程序注销为止。这是必需的,因为在成功登录后,令牌需要在每个后续的HTTP请求中传递。如上所述,我们将不使用任何客户端(浏览器)cookie来存储令牌。
相反,我们将在用户SESSION的服务器端存储令牌。创建一个SESSION变量并将令牌存储在其中。成功登录后,对于每个后续请求,我们将从session变量获取令牌并将其插入到传入的HTTP请求中。
我们将在HomeController下面的操作方法中执行此操作,从TokenProvider.cs中获取令牌,创建Session对象“JWToken”并存储令牌。
在HomeController.cs中,有一个“LoginUser”操作方法。用户可以从Index.cshtml输入用户ID和密码,并将页面提交到HomeController.cs中的“LoginUser”操作方法。在“LoginUser”控制器操作方法中,我们将令牌添加到会话对象名称“JWToken”。
HttpContext.Session.SetString("JWToken", userToken);
中间件
这是整个实现过程的关键部分。这部分更多是一个概念,几行代码。我们将在这里做两件事:
- 将令牌插入HTTP请求
- 将用户声明加载到HTTP请求中
首先让我们了解一下这个概念。为了保持简单,请忍受。
身份验证和授权通过HTTP请求进行处理,以实现以下目的:
- 令牌应该是HTTP请求的一部分,并且应该来自HTTP请求标头。
- ClaimsPrinciple和ClaimsIdentity(HttpContext.User.Identity)对象是从当前HTTP上下文创建的。
- 从HTTP请求标头读取用户声明并将其加载到HTTP Claims标识对象中
- 换句话说,授权是通过传入的HTTP请求完成的,而不是直接从令牌中读取。
- 这样,将为该用户授权HTTP请求。
要达到上述目的:
- 我们需要将Token(存储在用户会话变量“JWToken”中)插入每个传入的HTTP请求中。
- 从中读取用户声明值Token并将其加载到HTTP 上下文的Claims Principle对象中。
- 如果令牌在session变量“JWToken” 中不可用,则HTTP请求标头“Authorization”将为空。在这种情况下,不会在HTTP上下文中设置该用户的Claims Principle。那将拒绝用户的许可。
下图给出了有关如何将Token插入HTTP标头并在HTTP上下文中设置Claims Principle的想法。
自定义中间件app.Use()
使用此自定义中间件将令牌插入传入HTTP请求的主要思想。现在,我们已经记录了存储在Session变量“JWToken” 中的用户令牌,我们需要将该令牌插入所有后续传入的HTTP请求中。为此,我们将向ASP.NET Core中间件编写几行代码。这不过是HTTP管道。自定义中间件已添加到Startup.cs Configure()方法中。
PS:Token在用户登录期间仅创建一次。
中间件app.UseAuthentication()
现在,我们需要验证令牌并将声明加载到HTTP Request上下文。UseAuthentication()为我们做这项工作。在HTTP请求命中MVC控制器之前,UseAuthentication()执行以下操作:
- 使用AddJwtBearer()配置中提供的密钥解密和验证令牌(在Startup.cs中的ConfigureServices()方法下)
- 在HTTP请求上下文中设置User对象
- 最后,从Token中读取Claims值并将其加载到HttpContext.User.Identity对象
自定义中间件代码
在Startup.cs中,将以下代码添加到Configure()方法中。在之后添加以下代码app.UseCookiePolicy()。在这里,代码执行顺序很重要。
app.UseSession();
//Add JWToken to all incoming HTTP Request Header
app.Use(async (context, next) =>
{var JWToken = context.Session.GetString("JWToken");if (!string.IsNullOrEmpty(JWToken)){context.Request.Headers.Add("Authorization", "Bearer " + JWToken);}await next();
});
//Add JWToken Authentication service
app.UseAuthentication();
让我们看一下代码:
- app.UseSession()是使用Session对象配置的。
- 要编写自定义中间件,请使用app.Use()。
- 首先,在将其插入到HTTP Request中之前,我们需要Token。我们已将令牌存储在Session中。Token从session变量“JWToken”中获取。
var JWToken = context.Session.GetString("JWToken");
- 下一行检查在Session中Token是否可用。如果不可用,则用户未通过身份验证。因此,用户权限被拒绝。
- 如果Token出现在Session变量“JWToken”中,那么我们可以通过用户身份认证。
- 现在,我们需要将令牌添加到HTTP Request(请记住,用户标识(User Identity)是通过HTTP Request创建的)。以下代码将令牌添加到所有传入的HTTP Request中。
context.Request.Headers.Add("Authorization", "Bearer " + JWToken);
- 注意,我们将令牌添加到HTTP Request的“Authorization”标头中。是的,将令牌添加到“Authorization”标头很重要,并且令牌应与关键字“Bearer” 串联。
- 下一行代码是app.UseAuthentication()。
- 这行代码将查找在ConfigureServices()方法中配置的身份验证机制。在我们的ConfigureService()代码中,我们使用Microsoft.AspNetCore.Authentication namespace中的“AddJwtBearer”进行配置。
- 在AddJWtBeared()内部,我们具有带有密钥、到期日期等的令牌配置。
- 当HTTP Request进入时,app.UseAuthentication()将在HTTP Request中查找“Authorization”标头。它将读取存储在“Authorization”标头中的值,并将其传递给Microsoft.AspNetCore.Authentication。Microsoft.AspNetCore.Authentication将根据我们为令牌设置的配置评估和验证令牌。这包括使用我们在配置中提供的密钥对令牌解密,并从令牌中读取声明,并将声明加载到HttpContext.User.Identity对象。在这里,HTTP上下文本身是经过身份验证和授权的。
- 此完整执行仅对一个HTTP Request(特定的传入请求)有效。我们必须对所有后续HTTP Request执行此操作。这就是我们将Token存储在session变量中并将Token分配给所有后续传入HTTP Request 的HTTP Request“Authorization”标头的原因。所有传入的HTTP Request和传出的HTTP Response都通过Startup.cs Configure()方法中的HTTP管道进行。
最后,Startup.cs Configure()方法如下所示:
// This method gets called by the runtime.
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}else{app.UseExceptionHandler("/Home/Error");}app.UseStaticFiles();app.UseCookiePolicy();//Add User sessionapp.UseSession();//Add JWToken to all incoming HTTP Request Headerapp.Use(async (context, next) =>{var JWToken = context.Session.GetString("JWToken");if (!string.IsNullOrEmpty(JWToken)){context.Request.Headers.Add("Authorization", "Bearer " + JWToken);}await next();});//Add JWToken Authentication serviceapp.UseAuthentication();app.UseMvc(routes =>{routes.MapRoute(name: "default",template: "{controller=Home}/{action=Index}/{id?}");});
}
登录页面(Index.cshtml)
现在,我们创建一个带有用户ID和密码文本框的简单登录页面(Index.cshtml)。添加User.cs模型以查看页面。在这里,您可以看到检查用户是否已通过身份验证的IF条件User.Identity.IsAuthenticated。“User”对象是System.Security.Claims的一部分,由中间件在HTTP上下文中设置。如果用户已通过身份验证,我们将通过claims标识名称属性显示用户名。如果不是,那么我们要求用户登录。
@model LoginDemo.Models.User
@{ViewData["Title"] = "Home Page";
}
<div style="padding-top:50px;"></div>
<div style="padding-top:50px;">@if (User.Identity.IsAuthenticated){<div class="row">You are Logged in as<span style="font-size:large;color:forestgreen;">@User.Identity.Name</span></div><div class="row" style="padding-top:50px;">@Html.ActionLink("Log Off", "Logoff","Home", null, new { @class = "btn btn-primary btn-lg rph-login-button" })</div>}else{<div class="row"><div class="col-lg-4 col-md-4 col-sm-4"><div>@using (Html.BeginForm("LoginUser", "Home",FormMethod.Post, new { role = "form" })){<div>@Html.AntiForgeryToken()<div><label>User ID</label><br /></div><div>@Html.TextBoxFor(m => m.USERID,new {@class = "form-control txtbox"})</div><div style="padding-top:20px;"></div><div><label>Password</label><br /></div><div>@Html.PasswordFor(m => m.USERID,new {@class = "form-control txtbox"})</div></div><div class="padding-left:35%;width:40%;"><div class="padding-top:20px;"><input class="btn btn-primarybtn-lg rph-login-button"type="submit" value="Login"/></div></div>}</div></div><div class="col-lg-8 col-md-8 col-sm-8"><div style="padding-top:50px;"><div><b>Please login with any of the below User ID,Password is span style="font-size:large;color:forestgreen;">test</span> for all Users</b></div><div style="padding-top:10px;"><ui style="list-style: none;"><li>jsmith@email.com - Director, Read Only - true</li><li>srob@email.com - Supervisor, Read Only - false</li><li>dwill@email.com - Analyst, Read Only - false</li><li>JBlack@email.com - Analyst, Read Only - true</li></ui></div></div></div></div>}
</div>
Home控制器
让我们在HomeController.cs中添加两个Action方法。一个用于Index(登录)页面,另一个用于提交登录页面。
public IActionResult Index()
{return View();
}public IActionResult LoginUser(User user)
{TokenProvider _tokenProvider = new TokenProvider();//Authenticate uservar userToken = _tokenProvider.LoginUser(user.USERID.Trim(), user.PASSWORD.Trim());if (userToken != null){//Save token in session objectHttpContext.Session.SetString("JWToken", userToken);}return Redirect("~/Home/Index");
}
Action方法LoginUser(User user)从登录页面获取用户ID和密码值。下一行通过检查数据存储中的用户ID和密码来进行身份验证。
var userToken = _tokenProvider.LoginUser(user.USERID.Trim(), user.PASSWORD.Trim());
接下来的几行通过TokenProvider()检查是否存在发行的令牌。如果是,则将令牌保存在用户Session变量“JWToken”中。
if (userToken != null)
{//Save token in session objectHttpContext.Session.SetString("JWToken", userToken);
}
然后,将页面重定向到Index.cshtml:
return Redirect("~/Home/Index");
在页面重定向期间,我们已经将令牌存储在session对象中。现在,页面重定向通过Startup.cs中的HTTP管道进行。现在,自定义中间件将停止HTTP Request,并将令牌插入HTTP Request标头“Authorization”。请参阅“中间件”以获取更多详细信息(上面章节)。
如果token在session变量“JWToken” 中不可用,则HTTP Request标头“Authorization”将为空。在这种情况下,Context将不会为该用户设置HTTP 。重定向将要求用户登录。
注销(Log Off)
让我们注销用户。如果没有令牌,则无法为用户设置HTTP上下文。因此,token从session对象中删除。要从session中除去token,请清除该用户的session并重定向到另一个控制器动作。
添加一个控制器动作方法Logoff()。为用户清除session并重定向到Index操作方法中。重定向到另一个控制器操作方法很重要。让我们看看为什么?假设在Logoff()操作方法中,我们返回View()而不是Redirect()。在这种情况下,视图页面将呈现给浏览器,并且仍然用户可以访问该页面,User.Identity.IsAuthenticated仍然是true。当ASP.NET执行控制器操作方法时,它正在HTTP RESPONSE的过程中。这意味着它已经通过HTTP REQUEST传递了。用户 Claims Principle在HTTP Request中设置。通过注销用户,我们还需要清除该用户的Claims Principle。仅清除会话是不够的。因此,我们需要再次通过HTTP管道。重定向到另一个控制器通过HTTP管道,它将查找在session变量“JWToken”中的Token。但是,我们已经清除了session,token将不会在session中了。没有令牌,就不能在HTTP上下文中设置Claims Principle。这将完全注销用户。
public IActionResult Logoff()
{HttpContext.Session.Clear();return Redirect("~/Home/Index");
}
控制器代码
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using LoginDemo.Models;
using System.Security.Claims;
using Microsoft.AspNetCore.Http;namespace LoginDemo.Controllers
{public class HomeController : Controller{public IActionResult Index(){return View();}public IActionResult LoginUser(User user){TokenProvider _tokenProvider = new TokenProvider();var userToken = _tokenProvider.LoginUser(user.USERID.Trim(),user.PASSWORD.Trim());if (userToken != null){//Save token in session objectHttpContext.Session.SetString("JWToken", userToken);}return Redirect("~/Home/Index");}public IActionResult Logoff(){HttpContext.Session.Clear();return Redirect("~/Home/Index");}}
}
登录演示项目
登录页面
LoginDemo.sln
第2部分
在第2部分中,我们将介绍对用户的授权。我们将看到:
- 如何授予用户页面级访问权限
- 如何创建自定义授权过滤器属性以在控制器级别和操作方法级别上限制用户
- 用自定义授权属性装饰控制器操作方法
- 限制用户无需登录即可直接访问页面
下一篇:使用JWT的ASP.NET CORE令牌身份验证和授权(无Cookie)——第2部分
使用JWT的ASP.NET CORE令牌身份验证和授权(无Cookie)——第1部分相关推荐
- 使用JWT的ASP.NET CORE令牌身份验证和授权(无Cookie)——第2部分
目录 介绍 用户角色 如何创建自定义授权特性? AuthorizeAttribute AuthorizeFilter 如何在控制器和操作方法级别设置权限? 检查用户权限的扩展方法 如何在操作方法(内联 ...
- Asp.Net Core WebApi 身份验证、注册、用户管理
Asp.Net Core WebApi身份验证.注册.用户管理 用户服务 用户实体.用户模型及数据上下文 应用程序设置文件 在Startup.cs中配置身份验证 参考文献 用了两天的时间研究了在Asp ...
- ASP.NET Web API身份验证和授权
英语原文地址:http://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-a ...
- ASP.NET Core的身份认证框架IdentityServer4(3)-术语的解释
ASP.NET Core的身份认证框架IdentityServer4(3)-术语的解释 原文:ASP.NET Core的身份认证框架IdentityServer4(3)-术语的解释 IdentityS ...
- ASP.NET Core的身份认证框架IdentityServer4(4)- 支持的规范
原文:ASP.NET Core的身份认证框架IdentityServer4(4)- 支持的规范 IdentityServer实现以下规范: OpenID Connect OpenID Connect ...
- Angular之jwt令牌身份验证
Angular之jwt令牌身份验证 demo https://gitee.com/powersky/jwt 介绍 Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种 ...
- 自动化CodeReview - ASP.NET Core请求参数验证
自动化CodeReview系列目录 自动化CodeReview - ASP.NET Core依赖注入 自动化CodeReview - ASP.NET Core请求参数验证 参数验证实现 在做服务端开发 ...
- .NET6之MiniAPI(九):基于角色的身份验证和授权
身份验证是这样一个过程:由用户提供凭据,然后将其与存储在操作系统.数据库.应用或资源中的凭据进行比较. 在授权过程中,如果凭据匹配,则用户身份验证成功,可执行已向其授权的操作. 授权指判断允许用户执行 ...
- 【.NET框架实战】IdentityServer4身份验证、授权
[.NET框架实战]IdentityServer4身份验证.授权 什么是身份认证 身份认证是指当客户端访问服务端资源时,验证客户端是否合法的一种机制 什么是授权 授权就是指当客户端经过身份认证后,能够 ...
最新文章
- java 比较器comparator_Java中比较器的使用Compare和Comparator
- 20175317 《Java程序设计》第一周学习总结
- Android 动态生成 EditTest
- android开发应用知识,Android应用开发经常使用知识
- Linux学习笔记7
- 保存blob到本地_用12行代码提取浏览器自动保存的密码
- 血的教训--如何正确使用线程池submit和execute方法
- 2个recordset合并_史上最全!8种办法玩转Excel文字合并,总有一款适合你!
- mysql account locked_ORA-28000: the account is locked用户锁定问题排查解决
- 7-8 统计工龄 (20 分)
- opencv3编程入门-毛星云
- 笔记本电脑刚回来没有计算机,刚买笔记本电脑我的笔记本电脑没有光驱,如果重新安装系统,怎么样操 爱问知识人...
- 机械硬盘换固态硬盘重装系统
- 有道云笔记本 html,有道云笔记怎么保存网页 有道云笔记保存路径在哪
- coap 返回版本信息_coap组包格式的简单解析
- 1.1 win10下wget的安装
- 深读 | 《人人都是产品经理2.0》中篇
- 立体栅格地图_三维栅格地图构建之二:视差图及点云图 | 学步园
- u盘装服务器系统失败原因,u盘装系统引导失败原因及解决方案
- java中输出语句println()和print()的区别
热门文章
- python程序如何做界面_如何用Python给已有小程序做界面?
- oracle用户的追踪文件,Oracle中怎样通过触发器来追踪用户的活动?
- linux一次执行多个命令,linux 一次执行多条命令
- tpc-c 服务器性能,IBM创英特尔8处理器服务器TPC-C性能记录
- mysql核心技术分析_深入理解MySQL核心技术
- 服务器查看日志桌面版工具,系统日志查看工具(LogFusion Pro)
- matlab怎么设clim,Python Matplotlib.pyplot.clim()用法及代码示例
- android 混淆方法名,android – 如何告诉Proguard混淆类名
- python网络爬虫_Python即时网络爬虫:API说明
- virtio-fs: A Shared File System for Virtual Machines