一、先约定流程
- 前端登录:账号密码提交给后台
- 后台验证账号密码,生成 Token返回
- 前端把 Token 存进
localStorage - 后续所有 Ajax 请求自动在 Header 带上 Token
- 后台全局拦截器统一校验 Token,不合法直接拦截
二、后端部分 .NET MVC
1. 新建 Token 全局拦截器 TokenAuthAttribute.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace Net6MVC.Controllers
{
// 全局Token授权过滤器
public class TokenAuthAttribute : ActionFilterAttribute
{
// 模拟服务器有效Token(实际用Redis/数据库)
public static string ServerValidToken = "";
public override void OnActionExecuting(ActionExecutingContext context)
{
// 从请求头取 token
string token = context.HttpContext.Request.Headers["token"].FirstOrDefault() ?? "";
// 校验
if (string.IsNullOrEmpty(token) || token != ServerValidToken)
{
// 返回JSON(.NET6 标准写法)
//context.Result = new JsonResult(new { code = 401, msg = "登录已失效,请重新登录" });
// 关键:无效 → 强制跳转到 登录页面
context.Result = new RedirectToActionResult("Login", "Home", null);
return;
}
base.OnActionExecuting(context);
}
}
}
2. 控制器 HomeController
using Microsoft.AspNetCore.Mvc;
namespace Net6MVC.Controllers
{
public class HomeController : Controller
{
// 登录页
public IActionResult Index()
{
return View();
}
// 登录接口
public IActionResult Login(string userName, string pwd)
{
// 模拟验证
if (userName == "admin" && pwd == "123456")
{
// 生成Token
string token = Guid.NewGuid().ToString("N");
// 服务器保存
TokenAuthAttribute.ServerValidToken = token;
// .NET6 直接返回Json,无需多余参数
return Json(new
{
code = 200,
msg = "登录成功",
token = token
});
}
return Json(new
{
code = 500,
msg = "账号密码错误"
});
}
// 需要登录才能访问
[TokenAuth]
public IActionResult GetUserInfo()
{
return Json(new
{
code = 200,
name = "管理员",
age = 28
});
}
// 退出登录
public IActionResult Logout()
{
TokenAuthAttribute.ServerValidToken = "";
return Json(new
{
code = 200,
msg = "退出成功"
});
}
}
}
三、前端页面 完整代码
功能:
- 登录拿到 Token 存 localStorage
- 封装 Ajax 自动带 Header Token
- 请求受保护接口
- 退出清空本地 Token
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>NET6 MVC Token 登录</title>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
</head>
<body>
<input type="text" id="uname" value="admin" placeholder="账号"><br>
<input type="password" id="pwd" value="123456" placeholder="密码"><br>
<button id="btnLogin">登录</button>
<button id="btnGetInfo">获取用户信息</button>
<button id="btnLogout">退出</button>
<script>
// 封装Ajax:自动带Header Token
function myAjax(url, data, successCb) {
let token = localStorage.getItem("token") || "";
$.ajax({
url: url,
type: "get",
data: data,
headers: { "token": token },
dataType: "json",
success: function (res) {
if (res.code === 401) {
alert(res.msg);
localStorage.removeItem("token");
return;
}
successCb && successCb(res);
}
});
}
// 登录
$("#btnLogin").click(function () {
let uname = $("#uname").val();
let pwd = $("#pwd").val();
myAjax("/Home/Login", { userName: uname, pwd: pwd }, function (res) {
if (res.code === 200) {
alert("登录成功");
localStorage.setItem("token", res.token);
} else {
alert(res.msg);
}
});
});
// 获取用户信息(需登录)
$("#btnGetInfo").click(function () {
myAjax("/Home/GetUserInfo", {}, function (res) {
alert("姓名:" + res.name);
});
});
// 退出
$("#btnLogout").click(function () {
myAjax("/Home/Logout", {}, function (res) {
localStorage.removeItem("token");
alert("已退出");
});
});
</script>
</body>
</html>
四、整套逻辑关键点
- 后端
Request.Headers["token"]直接取请求头参数 - 拦截器统一校验,不用每个控制器写判断
- 前端
localStorage存 Token,封装 Ajax 自动带 Header - 未传 Token/Token 不匹配,直接拦截返回 401
- 退出时:清服务器 Token + 清前端 localStorage
1143

被折叠的 条评论
为什么被折叠?



