Cookies, Claims and Authentication in ASP.NET Core(转载)
Most of the literature concerning the theme of authentication in ASP.NET Core focuses on the use of the ASP.NET Identity framework. In that context, things don’t seem to have changed much or, more precisely, all the changes that occurred in the infrastructure have been buried in the folds of the framework so that it looks nearly the same on the surface.
If you look at user authentication in ASP.NET Core outside the comfortable territory of ASP.NET Identity, you might find it quite different from what it was in past versions. ASP.NET Identity is a full-fledged, comprehensive, big framework that's overkill if all you need is to authenticate users via plain credentials from a simple database table. In this case, you'll see that the overall approach to authentication is still based on familiar concepts such as principal, login form, challenge and authorization attributes, except that the way you implement them is radically different. In this month's column, I'll explore the cookie authentication API as made available in ASP.NET Core, including the core facts of external authentication.
Foundation of ASP.NET Authentication
In ASP.NET, user authentication involves the use of cookies. Any users that attempt to visit a private page are redirected to a login page if they don't carry a valid authentication cookie. The login page, after having verified provided creden-tials, emits the cookie, which then travels with any subsequent requests from that user through the same browser until it expires. This is the same basic workflow you might know from past versions of ASP.NET. In ASP.NET Core, it only looks different because of the different middleware and the different configuration of the runtime environment.
There are two major changes in ASP.NET Core for those coming from an ASP.NET Web Forms and ASP.NET MVC background. First, there's no longer a web.config file, meaning that configuration of the login path, cookie name and expiration is retrieved differently. Second, the IPrincipal object—the object used to model user identity — is now based on claims rather than the plain user name. To enable cookie authentication in a brand-new ASP.NET Core 1.x application, you first reference the Microsoft.AspNetCore.Authentication.Cookies package and then add the code snippet in Figure 1.
Figure 1 Registering Middleware for Cookie Authentication
// This code is for ASP.NET Core 1.x
public void Configure(IApplicationBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
AuthenticationScheme = "Cookies",
CookieName = "YourAppCookieName",
LoginPath = new PathString("/Account/Login"),
ExpireTimeSpan = TimeSpan.FromMinutes(),
SlidingExpiration = true,
ReturnUrlParameter = "original",
AccessDeniedPath = new PathString("/Account/Denied")
});
}
Most of the information that classic ASP.NET MVC applications stored in the <authentication> section of the web.config file are configured as middleware options. The snippet in Figure 1 comprehends canonical options you might want to choose. Figure 2 explains each in more detail.
Figure 2 Cookie Authentication Options
Property | Description |
AccessDeniedPath | Indicates the path where an authenticated user will be redirected if the provided identity doesn’t have permission to view the requested resource. The same as getting an HTTP 403 status code. |
AutomaticAuthenticate | Indicates the middleware runs on every request and attempts to validate cookie and build an identity object from content. |
AutomaticChallenge | Indicates the middleware redirects the browser to a login page if the user isn’t authenticated or to the access denied page if the user is authenticated but not authorized on the requested resource. |
AuthenticationScheme | Name of the middleware. This property works in conjunction with AutomaticChallenge to selectively pick up the authentication middleware on a per-request basis. |
CookieName | Name of the authentication cookie being created. |
ExpireTimeSpan | Sets the expiration time of the authentication cookie. Whether the time has to be intended as absolute or relative is determined by the value of the SlidingExpiration property. |
LoginPath | Indicates the path where an anonymous user will be redirected to sign in with her own credentials. |
ReturnUrlParameter | Name of the parameter being used to pass the originally requested URL that caused the redirect to the login page in case of anonymous users. |
SlidingExpiration | Indicates whether the ExpireTimeSpan value is absolute or relative. In the latter case, the value is considered as an interval and the middleware will reissue the cookie if more than half the interval has elapsed. |
注意上面这个表格的很多属性从ASP.NET Core 2.X开始,应该在Startup类的ConfigureServices方法中进行设置,例如下面就演示了如何在ASP.NET Core 2.X中设置Cookie认证的Cookie名字:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//注册Cookie认证服务
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(option =>
{
option.Cookie.Name = "AspNetCookieAuth";//设置Cookie认证的Cookie名字
}); services.AddMvc();
}
Note that path properties are not of type string. LoginPath and AccessDeniedPath are of type PathString, which, compared to the plain String type, provides correct escaping when building a request URL.
The overall design of the user authentication workflow in ASP.NET Core gives you an unprecedented amount of flexi-bility. Every aspect of it can be customized at will. As an example, let's see how you can control the authentication work-flow being used on a per-request basis.
Dealing with Multiple Authentication Schemes
By setting AutomaticChallenge to false, you instruct the middleware not to react to the [Authorize] challenges by per-forming, say, a redirect. If no middleware will handle the challenge an exception is thrown. Automatic challenge was the norm in past versions of ASP.NET and there was almost nothing you could do about it.
In ASP.NET Core, you can register multiple and distinct pieces of authentication middleware and determine either algorithmically or via configuration which middleware has to be used for each request. When multiple authentication middleware is used, Automatic Authenticate can be true on multiple middleware. AutomaticChallenge, instead, should only be enabled on zero or one middleware. For more details, see bit.ly/2tS07Sm.
Common examples of authentication middleware are cookie-based authentication, bearer authentication, authentication through social networks, or an identity server and whatever else you can ever think to implement. Suppose you have the following code in the Configure method of your startup class:
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationScheme = "Cookies",
LoginPath = new PathString("/Account/Login/"),
AutomaticAuthenticate = true
});
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
AuthenticationScheme = "Bearer",
AutomaticAuthenticate = true
}
Be aware that there are constants to be used in place of magic strings like "Cookies" just to limit typos. In particular, the string "Cookies" can be replaced as below:
AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme
Note that UseIdentityServerAuthentication isn't part of the ASP.NET Core framework but belongs to the Identity Server framework (see github.com/IdentityServer). To choose the authentication scheme on a per-request basis, you use a new attribute on the Authorize attribute that in ASP.NET MVC marks actions as subject to authentication and authorization:
[Authorize(ActiveAuthenticationSchemes = "Bearer")]
public class ApiController : Controller
{
// Your API action methods here
...
}
The net effect of the code snippet is that all public endpoints of the sample ApiController class are subject to the identity of the user as authenticated by the bearer token.
Modeling the User Identity
In ASP.NET, the IPrincipal interface defines the software contract that defines the core of the user identity. The logged user is exposed through the User property of the HttpContext controller property. IPrincipal has the same implementation in ASP.NET 4.x (including ASP.NET MVC) and ASP.NET Core. However, in ASP.NET Core the default principal object isn't GenericPrincipal, but the new ClaimsPrincipal type. The difference is relevant.
GenericPrincipal wraps up one key piece of user information—the user name—even though custom user data can be added to the authentication ticket encrypted in the cookie. Over the years, the sole user name has become too little for the needs of modern applications. The role of the user, as well as some other chunks of information, most noticeably picture and display name, appear absolutely required today, forcing every realistic application to create its own custom principal type or query user information for each and every request using the user name as the key. ClaimsPrincipal just brilliantly solves the problem.
A claim is a key/value pair that describes a property of the logged user. The list of properties is up to the application, but includes name and role at the very minimum. Claims, in other words, are the ASP.NET Core way to model identity information. Claims can be read from any source, whether databases, cloud or local storage, even hardcoded. The Claim class is as simple as this:
public class Claim
{
public string Type { get; }
public string Value { get; } // More properties ...
}
The login process in ASP.NET Core passes through three classes: Claim, ClaimIdentity and ClaimsPrincipal.
Collecting the list of claims is a simple matter of populating an array of Claim objects:
public Claims[] LoadClaims(User user)
{
var claims = new[]
{
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.Role, user.Role),
new Claim("Picture", user.Picture)
};
return claims;
}
The name of the claim is a plain descriptive name rendered as a string. However, most common claim types have been grouped as constants into the ClaimTypes class. Before you create the principal, which is required to call the authentication workflow completed, you must get hold of an identity object:
var identity = new ClaimsIdentity(claims, "Password");
The first argument is self-explanatory—the list of claims associated with the identity being created. The second argument is a string that refers to the authentication scheme required to verify the identity. The string "Password" is a reminder of what will be required by the system for a user to prove her identity. The string "Password" is informational only and not a syntax element.
Another interesting aspect of the previous example is that an explicit user name is not strictly required. Any claim, regardless of the declared type, can be used to name the user. The following code snippet shows another equivalent way to have a new identity object:
var identity = new ClaimsIdentity(claims,
CookieAuthenticationDefaults.AuthenticationScheme,
"Nickname",
ClaimTypes.Role);
The new identity has "Cookies" as the authentication scheme and Nickname is the name of the claim in the provided list to be used to provide the name of the user. Role, instead, is the name of the claim in the same list determining the role. If not specified, the last two parameters default to ClaimTypes.Name and ClaimTypes.Role. Finally, you create the principal from the identity. It's worth noting, though, that a principal may have multiple identities. If it sounds weird, think that different areas of the same application might need different information to authenticate the user in much the same way an ID is required to identify yourself at some hotel desks and an electronic key to get into the elevator. The ClaimsPrincipal class has both an Identities property (a collection) and an Identity property. The latter is only a reference to the first item in the collection.
External Authentication
ASP.NET Core supports external authentication via identity providers from the ground up. Most of the time, all you do is install the appropriate NuGet package for the task. To rely on Twitter for authenticating users, you bring in the Microsoft.AspNetCore.Authentication.Twitter package and install the related middleware:
app.UseTwitterAuthentication(new TwitterOptions()
{
AuthenticationScheme = "Twitter",
SignInScheme = "Cookies",
ConsumerKey = "...",
ConsumerSecret = "..."
});
The SignInScheme property is the identifier of the authentication middleware that will be used to persist the resulting identity. In the example, an authentication cookie will be used. To see its effects, you first add a controller method to call into Twitter:
public async Task TwitterAuth()
{
var props = new AuthenticationProperties
{
RedirectUri = "/"
};
await HttpContext.Authentication.ChallengeAsync("Twitter", props);
}
Next, once Twitter has successfully authenticated the user, the SignInScheme property instructs the application on what to do next. A value of "Cookies" is acceptable if you want a cookie out of the claims returned by the external provider (Twitter, in the example). If you want to review and complete the information through, say, an intermediate form, then you have to break the process in two, introducing a temporary sign-in scheme. In addition to the standard cookie middleware you have the following:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationScheme = "ExternalCookie",
AutomaticAuthenticate = false
});
app.UseTwitterAuthentication(new TwitterOptions
{
AuthenticationScheme = "Twitter",
SignInScheme = "ExternalCookie"
});
When the external provider returns, a temporary cookie is created using the ExternalCookie scheme. Having set the redirect path appropriately, you have a chance to inspect the principal returned by Twitter and edit it further:
var props = new AuthenticationProperties
RedirectUri = "/account/external"
};
To complete the workflow you also need to sign in in the cookies scheme and sign out of temporary scheme (ExternalCookie):
public async Task<IActionResult> External()
{
var principal = await HttpContext
.Authentication
.AuthenticateAsync("ExternalCookie");
// Edit the principal
... await HttpContext.Authentication.SignInAsync("Cookies", principal);
await HttpContext.Authentication.SignOutAsync("ExternalCookie "); return View();
}
ExternalCookie, as well as cookies, are just internal identifiers and can be renamed as long as they remain consistent throughout the application.
Wrapping Up
In ASP.NET Core many things seem to be radically different, but in the end most of the concepts you might know from ASP.NET remain unchanged. You still need to have an authentication cookie created, and you can still control the name of the cookie and the expiration date. External authentication is supported and login pages have the same structure as before. However, configuration and underlying working of the authentication infrastructure are different, while retaining their previous flexibility.
Everything stated in this article refers to ASP.NET Core 1.x. There are a few things that will work differently in ASP.NET Core 2.0. In particular, authentication middleware is now exposed as services and must be configured on Configure-Services:
services.AddCookieAuthentication(options =>
{
Options.LoginPath = new PathString("/Account/Login"),
options.AutomaticAuthenticate = true,
options.AutomaticChallenge = true,
options.AuthenticationScheme = "Cookies",
...
});
In the Configure method of the Startup class of ASP.NET Core 2.0 applications, you just declare your intention to use authentication services without any further options:
app.UseAuthentication();
Also note that the SignInAsync method you use in your code to create the authentication cookie is also exposed from the HttpContext object directly, instead of passing through an intermediate Authentication property as shown in the last code snippet for ASP.NET Core 1.x.
Cookies, Claims and Authentication in ASP.NET Core(转载)的更多相关文章
- 5.3Role和Claims授权「深入浅出ASP.NET Core系列」
希望给你3-5分钟的碎片化学习,可能是坐地铁.等公交,积少成多,水滴石穿,码字辛苦,如果你吃了蛋觉得味道不错,希望点个赞,谢谢关注. Role授权 这是一种Asp.Net常用的传统的授权方法,当我们在 ...
- ASP.NET CORE中使用Cookie身份认证
大家在使用ASP.NET的时候一定都用过FormsAuthentication做登录用户的身份认证,FormsAuthentication的核心就是Cookie,ASP.NET会将用户名存储在Cook ...
- ASP.NET Core Authentication系列(一)理解Claim, ClaimsIdentity, ClaimsPrincipal
前言 首先我们来看一下在ASP.NET时代,Authentication是如何使用的.下面介绍的是System.Web.Security.FormsAuthentication: // 登录 Syst ...
- ASP.NET Core Authentication系列(二)实现认证、登录和注销
前言 在上一篇文章介绍ASP.NET Core Authentication的三个重要概念,分别是Claim, ClaimsIdentity, ClaimsPrincipal,以及claims-bas ...
- ASP.NET Core 中的那些认证中间件及一些重要知识点
前言 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系列(一,二,三)奠定一下基础. 有关于 Authentication 的知识太广,所以本篇介绍几个在 A ...
- [转]ASP.NET Core 中的那些认证中间件及一些重要知识点
本文转自:http://www.qingruanit.net/c_all/article_6645.html 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系 ...
- ASP.NET Core 使用Cookie验证身份
ASP.NET Core 1.x提供了通过Cookie 中间件将用户主体序列化为一个加密的Cookie,然后在后续请求中验证Cookie并重新创建主体,并将其分配给HttpContext.User属性 ...
- ASP.NET Core 认证与授权[4]:JwtBearer认证
在现代Web应用程序中,通常会使用Web, WebApp, NativeApp等多种呈现方式,而后端也由以前的Razor渲染HTML,转变为Stateless的RESTFulAPI,因此,我们需要一种 ...
- ASP.NET Core 身份验证(一)
前言 这篇文章我想带领大家了解一下 ASP.NET Core 中如何进行的身份验证,在开始之前强烈建议还没看过我写的 Identity 系列文章的同学先看一下. Identity 入门系列文章: Id ...
随机推荐
- 细说 JavaScript 七种数据类型
在 JavaScript 规范中,共定义了七种数据类型,分为 “基本类型” 和 “引用类型” 两大类,如下所示: 基本类型:String.Number.Boolean.Symbol.Undefined ...
- 【Python实践-2】求一个或多个数的乘积
# -*- coding: utf-8 -*- #定义一个函数,可接收一个或多个数并计算乘积 def product(*numbers): s=1 for n in numbers: s=s*n re ...
- 7. VIM 系列 - 程序员利器(语法检测、代码块补全、symbol管理、函数跳转)
目录 1. 语法检查利器 ale 2. 补全代码块 3. symbol 管理器 taglist.vim 4. 函数跳转 1. 语法检查利器 ale 安装 ale Plug 'w0rp/ale' 配置 ...
- java中的int与byte的转化
java中的int与byte的转化 1.基础准备 1.1.原码 就是二进制码,最高位为符号位,0表示正数,1表示负数,剩余部分表示真值 1.2.反码 在原码的基础上,正数反码就是他本身,负数除符号位之 ...
- TabTopLayout【自定义顶部选项卡区域(固定宽度且居中)】
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 自定义顶部选项卡并居中显示.结合显示/隐藏view的方式实现切换功能(正常情况下可能是切换fragment). 效果图 代码分析 T ...
- JavaScript夯实基础系列(二):闭包
在JavaScript中函数是一等公民.所谓一等公民是指函数跟其他对象一样,很普通,可以进行把函数存在数组中.作为参数传递.赋值给变量等操作.当函数作为另一个函数的返回值在外部调用时,跟该函数在函 ...
- [转]Blue Prism Interview Questions and Answers
本文转自:https://www.rpatraining.co.in/blue-prism-interview-questions/ What is a Visual Business Object? ...
- 分享几个常见的CMD命令,可能会用的上
win7快捷命令.CMD命令secpol.msc(设置开机启动提示信息)services.msc(打开服务)dxdiag(检查DirectX信息)winver(检查Windows版本)regedit( ...
- C#连接基于Java开发IM——Openfire
Openfire简介 Openfire 是开源的.基于可拓展通讯和表示协议(XMPP).采用Java编程语言开发的实时协作服务器.Openfire的效率很高,单台服务器可支持上万并发用户. ...
- Java 设置PDF文档背景色
一般生成的PDF文档默认的文档底色为白色,我们可以通过一定方法来更改文档的背景色,以达到文档美化以及保护双眼的作用. 以下内容提供了Java编程来设置PDF背景色的方法.包括: 设置纯色背景色 设置图 ...