1、环境说明
.net sdk6.0
vs2022
2、Program.cs配置
一是配置AddAntiforgery自定义的HeaderName,因为这是.net corede的默认的预防跨网站请求伪造 (XSRF/CSRF) 攻击的手段,关闭了也不太好,所以添加自定义的头。
二是Cookie认证的配置,如果不喜欢用Cookie,可以自己改成jwt之类的。
builder.Services.AddAntiforgery(o => o.HeaderName = "RequestVerificationToken");
#region Cookie认证配置
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies"; // 默认使用Cookie认证
options.DefaultChallengeScheme = "Cookies"; // 默认的质询方案(未登录时使用的方案)
})
.AddCookie("Cookies", options =>
{
options.LoginPath = "/User/UserLogin"; // 登录页面路径
options.AccessDeniedPath = "/User/AccessDenied"; // 拒绝访问页面路径
options.ExpireTimeSpan = TimeSpan.FromHours(2); // Cookie过期时间
options.SlidingExpiration = true; // 滑动过期
});
#endregion
3、UserLogin.cshtml
下面是页面部分代码,核心在于@Html.AntiForgeryToken()。
以及ajax请求的部分:重要的一是url,而是header的部分。
url不能错,网页的命名空间也不能错,错了就会返回html。
@page
@model chocolate_web.Pages.User.UserLoginModel
@{
ViewData["Title"] = "用户登录";
}
@Html.AntiForgeryToken()
@section Scripts
{
<script type="text/javascript">
// 初始化 Toast
const toastEl = document.querySelector('.toast');
const toast = new bootstrap.Toast(toastEl);
$(document).ready(function () {
$('#registrationButton').click(function(){
if($('#username').val() === "")
{
$('.toast-body').html("请输入账号!"),
toast.show();
return;
}
if($('#password').val() === "")
{
$('.toast-body').html("请输入密码!"),
toast.show();
return;
}
// 获取表单数据
var formData = {
account: $('#username').val(),
password: $('#password').val(),
rememberMe: false,//$('#remember_me').is(':checked')
};
// 禁用提交按钮
$('#registrationButton').prop('disabled', true);
$('#registrationButton').text('登录中...');
// 发送登录请求
$.ajax({
url: '?handler=Login',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(formData),
headers: {
"RequestVerificationToken": $('input[name="__RequestVerificationToken"]').val()
},
success: function (response) {
if (response.success) {
// 登录成功
window.location.href = response.returnUrl; // 重定向
} else {
$('.toast-body').html(response.message),
toast.show();
$('#registrationButton').prop('disabled', false);
$('#registrationButton').text('登录');
}
},
error: function (xhr) {
//toast.show();
//alert('登录失败,请稍后重试');
},
complete: function () {
// 恢复提交按钮
$('#registrationButton').prop('disabled', false);
$('#registrationButton').text('登录');
}
});
});
});
</script>
}
4、UserLogin.cshtml.cs
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Security.Claims;
using Core_Database.EFCodeFirstDAL;
using Core_Database.InModel;
using Core_Database.Utils;
namespace chocolate_web.Pages.User
{
/// <summary>
/// 用户登录页面
/// </summary>
public class UserLoginModel : PageModel
{
public void OnGet(string ReturnUrl = null)
{
TempData["ReturnUrl"] = ReturnUrl;
// 如果用户已经登录,重定向到首页
if (User.Identity.IsAuthenticated)
{
Response.Redirect(ReturnUrl==null ? "/User/UserCenter" : ReturnUrl);
}
}
public async Task<IActionResult> OnPostLoginAsync([FromBody] UserLogModel model)
{
var ReturnUrl = TempData["ReturnUrl"];
if (ModelState.IsValid)
{
try
{
// 验证用户名和密码
这里自定义的方法
string token = UtilsTools.CalculateMD5(UtilsTools.CalculateMD5(model.password) + user.salt);
if (!user.password.Equals(token))
{
return new JsonResult(new { success = false, message = "用户名或密码错误" });
}
// 创建身份声明
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.account),
new Claim(ClaimTypes.NameIdentifier, user.id.ToString()),
// 可以根据需要添加更多声明,比如角色等
new Claim("TrueName", user.truename ?? string.Empty)
};
var claimsIdentity = new ClaimsIdentity(claims, "Cookies");
var authProperties = new AuthenticationProperties
{
IsPersistent = model.rememberMe, // 是否记住登录状态
ExpiresUtc = model.rememberMe ? DateTimeOffset.UtcNow.AddDays(7) : DateTimeOffset.UtcNow.AddHours(2)
};
await HttpContext.SignInAsync("Cookies", new ClaimsPrincipal(claimsIdentity), authProperties);
//if(ReturnUrl != null && Url.IsLocalUrl(ReturnUrl.ToString()))
//{
// return RedirectToPage(ReturnUrl.ToString());
//}
//else
//{
// return RedirectToPage("/User/UserCenter");
//}
//返回登录成功信息和重定向URL
return new JsonResult(new
{
success = true,
message = "登录成功",
returnUrl = (ReturnUrl != null && Url.IsLocalUrl(ReturnUrl.ToString())) ? ReturnUrl.ToString() : "/User/UserCenter"
});
}
catch (Exception ex)
{
return new JsonResult(new { success = false, message = "登录失败:" + ex.Message });
}
}
else
{
return new JsonResult(new { success = false, message = "登录失败"});
}
}
/// <summary>
/// 退出登录
/// </summary>
/// <returns></returns>
public async Task<IActionResult> OnPostLogoutAsync()
{
await HttpContext.SignOutAsync("Cookies");
return new JsonResult(new { success = true, message = "已退出登录" });
}
}
}
5、没有登录不允许访问的页面
[Authorize]
public class UserCenterModel : PageModel
{
public void OnGet()
{
}
}
