鉴权授权
授权背景介绍
为了保护我们的服务器资源,给被访问的资源或接口添加限制,让每一个请求不能随意访问 服务或 API 或 Action 方法。一般的过程是用户在客户端登录确认身份,向服务器发送登录信息从而验证这个人是否有登录权限。
在ASP.NET中,授权(Authorization)是确定当前用户是否被允许访问特定资源的过程。授权通常在身份验证之后发生,确保用户具有执行某些操作的权限。
Http协议无状态
HTTP请求被设计为无状态协议,意味着每个请求都是独立的,服务器不会在两个请求之间保留任何上下文信息。这是为了简化服务器的设计和提高可伸缩性。然而,有几种方法可以在不同的HTTP请求之间共享信息:
- 使用Cookies:服务器可以在HTTP响应中设置Cookies,浏览器会存储这些Cookies并在后续的HTTP请求中将它们发送到服务器。
- 使用Session:在服务器端,可以为每个用户创建一个会话(session)对象来存储在不同请求之间需要共享的信息。
- 使用URL参数:在URL中传递信息,通常用于GET请求。
- 使用POST数据:POST请求可以在请求体中发送数据。
- 使用HTTP头部:可以自定义头部来传递额外的信息,如认证令牌等。
- 使用Web存储API:例如localStorage或sessionStorage,在客户端存储数据。
- 使用WebSockets:这是一个全双工通信协议,可以在客户端和服务器之间建立一个持续的连接,从而可以在多个请求之间共享状态。
ASP.NET Core传统授权的基本配置
使用中间件:
app.UseAuthentication();
app.UseAuthorization();
在 Program 中添加配置鉴权:
public class FourthController : Controller
{
/// <summary>
/// 正常访问的页面
/// </summary>
/// <returns></returns>
[Authorize]
public IActionResult Index()
{
return View();
}
/// <summary>
/// 登录页
/// </summary>
/// <returns></returns>
[HttpGet]
public IActionResult Login()
{
return View();
}
}
在浏览器输入 http://localhost:5999/Fourth/Index
因为Index 添加了[Authorize],在鉴权时只要找到用户信息就可以访问,否则跳转到 Login 页面 。
简单的登录功能
添加 model
public class CurrentUser
{
public int Id { get; set; }
[Display(Name = "用户名")]
public string? Name { get; set; }
public string? Account { get; set; }
[Display(Name = "密码")]
public string? Password { get; set; }
[DataType(DataType.EmailAddress)]
[Display(Name = "E-mail")]
public string? Email { get; set; }
public DateTime LoginTime { get; set; }
}
登录页面
@using Learn.NET6.Project.Models;
@model CurrentUser
@{
ViewBag.Title = "登录";
}
<h2>登录</h2>
<div class="row">
<div class="col-md-8">
<section id="loginForm">
@using (Html.BeginForm("Login", "Fourth", new { sid = "123", Account = "yika" },
FormMethod.Post, true, new { @class = "form-horizontal", role = "form" }))
{
@Html.AntiForgeryToken()
<hr />
@Html.ValidationSummary(true)
<div class="mb-3 row">
@Html.LabelFor(m => m.Name, new { @class = "col-sm-1 col-form-label" })
<div class="col-md-6">
@Html.TextBoxFor(m => m.Name, new { @class = "form-control", @placeholder = "请输入您的用户名" })
</div>
</div>
<div class="mb-3 row">
@Html.LabelFor(m => m.Password, new { @class = "col-md-1 control-label" })
<div class="col-md-6">
@Html.PasswordFor(m => m.Password, new { @class = "form-control", @placeholder = "请输入密码" })
</div>
</div>
<div class="mb-3 row">
<div class="col-md-offset-2 col-md-6">
<button type="submit" class="btn btn-primary mb-3">登录</button>
@base.ViewBag.Msg
</div>
</div>
}
</section>
</div>
</div>
点击按钮提交
/// <summary>
/// 提交
/// </summary>
/// <param name="name"></param>
/// <param name="password"></param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> Login(string name, string password)
{
if ("yika".Equals(name) && "1".Equals(password))
{
var claims = new List<Claim>()//鉴别你是谁,相关信息
{
new Claim("Userid","1"),
new Claim(ClaimTypes.Role,"Admin"),
new Claim(ClaimTypes.Role,"User"),
new Claim(ClaimTypes.Name,$"{name}--来自于Cookies"),
new Claim(ClaimTypes.Email,$"19998888698@163.com"),
new Claim("password",password),//可以写入任意数据
new Claim("Account","Administrator"),
new Claim("role","admin"),
new Claim("QQ","1025025050")
};
ClaimsPrincipal userPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, "Customer"));
HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, userPrincipal, new AuthenticationProperties
{
ExpiresUtc = DateTime.UtcNow.AddMinutes(30),//过期时间:30分钟
}).Wait();
var user = HttpContext.User;
return base.Redirect("/Fourth/Index");
}
else
{
base.ViewBag.Msg = "用户或密码错误";
}
return await Task.FromResult<IActionResult>(View());
}