ASP.NET Web的 Razor Pages应用,ajax调用记录以及Cookie配置

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()
     {
     }
 }
相关推荐
哀木1 小时前
一个简单的套壳方案,就能让你的 Agent 少做重复初始化
前端
问心无愧05131 小时前
ctf show web入门27
前端
小村儿1 小时前
给 AI Agent 装上"长期记忆":Karpathy 的 LLM Wiki 思想,我做成了工具
前端·后端·ai编程
竹林8181 小时前
用ethers.js连接MetaMask实现Web3钱包登录:从踩坑到稳定运行的完整记录
前端·javascript
heyCHEEMS1 小时前
如何用 Recast 实现静态配置文件源码级读写
前端·node.js
心连欣1 小时前
从零开始,学习所有指令!
前端·javascript·vue.js
review445431 小时前
大模型和function calling分别是如何工作的
前端
东东同学1 小时前
耗时一个月,我把 Nuxt 首屏性能排障经验做成了一个 AI Skill
前端·agent
冴羽2 小时前
超越 Vibe Coding —— AI 辅助编程指南
前端·ai编程·vibecoding
梦想的颜色3 小时前
一天一个SKILL——前端最佳自动化测试 webapp-testing
前端·web app