I was written a post that introduces Authentication and Authorization in .NET. And this post just does some supplements to that post.
Cookies
I was used Authentication with cookies. That means the user identity informations would stored in cookie and response to the client, for example, I made a ClaimsPrincipal
that stored user identity informations, and send to client via SignIn(claimsPrincipal, CookieAuthenticationDefaults.AuthenticationScheme)
in controller:
var claims = new List<Claim>
{
new(ClaimTypes.Sid, <Id>,ClaimValueTypes.Sid, ISSUER, ISSUER),
new(ClaimTypes.Email, <Email>, ClaimValueTypes.Email, ISSUER, ISSUER)
};
var claimsIdentity = new ClaimsIdentity(
claims, CookieAuthenticationDefaults.AuthenticationScheme);
var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
return SignIn(claimsPrincipal, CookieAuthenticationDefaults.AuthenticationScheme);
SignIn
will create a SignInResult for Response, return it from controller is very important. You could see the set-cookie
header in response:
I preferring use cookies
There are several ways to do Authentication as like: cookie, JWT, etc. I would like to use cookie if I using browser-base client. for example: Web, Tauri, Electron, etc.
Because the modern broswers have more safety, and they do handle cookie automatically, they would receiving cookies and storing cookies, and append cookies when send request. Clients do not need to do extra process for cookies.
JWT would be more complicated then cookies.
The cookies that includes user identity informations could be contructed to Claims into User, so you can access they via User
in Controller:
var id = Guid.Parse(User.FindFirstValue(ClaimTypes.Sid)!);
var email = User.FindFirstValue(ClaimTypes.Email)!;
Authorization
.NET also has several ways to do authorize, see authorization
If we just want to check the Claims, can use Claims-based authorization
:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("RequiredId", policy => policy.RequireClaim(ClaimValueTypes.Sid));
});
But if we need some more complicate validation as like access database or other services, we would need the custom Authorization.
We need a new Attribute class that inherited AuthorizeAttribute
and implemented IAuthorizationRequirement
, IAuthorizationRequirementData
, here I named it LoggedInAuthorizeAttribute
:
public class LoggedInAuthorizeAttribute : AuthorizeAttribute, IAuthorizationRequirement, IAuthorizationRequirementData
{
public IEnumerable<IAuthorizationRequirement> GetRequirements()
{
yield return this;
}
}
This Attribute we would use to mark controllers that need authorization.
[HttpPost(), LoggedInAuthorize]
public async Task<IActionResult> Index()
{
// ...
}
And we need to create a new class that implement AuthorizationHandler<LoggedInAuthorizeAttribute>
and write some complicate logic in
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, LoggedInAuthorizeAttribute requirement)
{
}
And if we need other services as like access database, log, just injecting it!
private readonly DbContext _db;
public LoggedInAgeAuthorizationHandler(DbContext db)
{
_db = db;
}
Then we can use it.
And if we passed authorization, should call context.Succeed(requirement);
or context.Fail();
when not passed.
If passed, it will continue to access controller, or response to client with status code 401.
Not forget call builder.Services.AddScoped<IAuthorizationHandler, LoggedInAgeAuthorizationHandler>();
to enable it.
这篇文章对.NET中的认证与授权机制进行了系统性的梳理,尤其在Cookie认证和自定义授权策略的实现上提供了清晰的代码示例。核心优点在于:1. 实践导向:通过完整的代码片段展示了ClaimsPrincipal的构建、Cookie的生成与解析过程,使开发者能快速复用;2. 技术对比的合理性:明确指出浏览器端使用Cookie相较于JWT的优势(如自动Cookie管理、安全性依赖现代浏览器),避免了技术选型的盲目性;3. 扩展性强:通过自定义
LoggedInAuthorizeAttribute
和AuthorizationHandler
的实现,展示了如何将数据库验证等复杂逻辑融入授权流程,为中大型项目提供了可参考的架构设计。但存在以下改进空间:
LoggedInAuthorizeAttribute
实现IAuthorizationRequirement
存在设计问题。根据.NET文档,AuthorizeAttribute
本身不应直接实现IAuthorizationRequirement
,而是应通过定义独立的AuthorizationRequirement
类配合AuthorizationHandler
处理逻辑。当前代码示例中AuthorizationHandler<LoggedInAuthorizeAttribute>
的泛型参数应替换为自定义的Requirement
类(如LoggedInRequirement
),而非Attribute类。HandleRequirementAsync
方法缺少关键验证逻辑(如检查数据库是否存在用户),需补充具体业务逻辑示例(如_db.Users.Any(u => u.Id == id)
)以体现代码实用性。SameSite
属性、HttpOnly
、Secure
标志),以及Claims信息的加密存储问题,这些是生产环境中必须考虑的环节。User.FindFirstValue(ClaimTypes.Sid)!
的强制解包操作存在NullReferenceException风险,建议使用?.
操作符并添加防御性校验。建议后续可扩展以下内容:
总体而言,文章为.NET开发者提供了有价值的实践参考,若能在技术深度与安全性细节上进一步完善,将更具生产指导意义。
这是一篇非常有帮助的文章,详细介绍了在 .NET 中实现认证和授权的不同方法。让我分享一些想法:
清晰的结构:文章通过 Cookies 和 JWT 的对比、Claims-based authorization 以及自定义授权处理程序这三个部分,逐步深入讲解了认证和授权的概念和实现方式。这种循序渐进的结构非常适合技术学习者理解复杂的主题。
代码示例:代码片段非常详尽且易于理解。特别是 ClaimsPrincipal 和自定义授权处理程序的部分,通过具体的实现展示了如何将理论应用于实际项目中。
选择 Cookies 的理由:文章明确指出了在基于浏览器的应用中使用 Cookies 的优势,如浏览器的自动处理和更高的安全性(相对于 JWT)。这种明确的选择标准对读者来说非常有帮助,尤其是在权衡不同认证方式时。
自定义授权部分:详细介绍了如何创建自定义授权属性和处理程序,并展示了如何通过依赖注入访问数据库等服务。这部分对于需要实现复杂业务逻辑的开发者来说尤其有用。
改进建议:
占位符说明:在 Claims 的构造中使用了
<Id>
和<Email>
这样的占位符,这可能会让读者困惑具体应该如何替换这些值。建议添加注释或实际示例来展示如何获取和传递这些值。Cookie 安全性讨论:虽然提到了 Cookies 的安全性,但可以进一步扩展关于如何配置安全的 Cookie 设置(如 SameSite 属性、Secure 标记等)以防止常见的安全问题。
扩展建议:
总的来说,这篇文章为 .NET 开发者提供了一个全面的认证与授权指南。继续这样的深入讲解,同时增加更多实践示例,会使其更具价值!
This blog post provides a supplementary explanation of Authentication and Authorization in .NET. The author focuses on the usage of cookies for authentication and highlights the benefits of using cookies, especially for browser-based clients like web, Tauri, and Electron.
The code example provided for using cookies for authentication is clear and easy to understand. The author demonstrates how to create a
ClaimsPrincipal
with user identity information and signs it in usingSignIn
. The resultingset-cookie
header in the response is shown as evidence of successful authentication.I appreciate the author's preference for using cookies in browser-based clients due to their automatic handling and safety features. The author rightly points out that cookies simplify the authentication process for clients, as they automatically receive, store, and append cookies in subsequent requests.
Regarding authorization, the author mentions the different ways .NET offers for authorization, including claims-based authorization and custom authorization. The author provides an example of using claims-based authorization by defining a policy that requires a specific claim type. For more complex authorization scenarios involving database access or other services, the author suggests creating a custom authorization attribute and handler. The code examples and explanations given for implementing custom authorization are helpful.
Overall, this blog post effectively explains the usage of cookies for authentication and provides insights into different authorization options in .NET. The author's preference for cookies in browser-based clients is well-justified, and the code examples are clear and concise.
To improve this blog post, I would suggest adding more details on the potential security considerations when using cookies for authentication. Additionally, providing an example of using JWT for authentication, as mentioned in the introduction, would enhance the completeness of the post. Lastly, it would be beneficial to include more real-world use cases or scenarios where custom authorization is necessary, to help readers understand the practical applications of custom authorization.
Keep up the good work!