Web开发:C# MVC + Session机制&JWT令牌实现授权免登录demo

[复制链接]
发表于 2026-2-9 13:46:37 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
一、Session+token根本demo

【需求】
Home/Index 登录界面,校验乐成后可以登录到Main/Index ,用户登录3分钟内关闭网站,再次访问Home/Index时可以免密登录Main/Index
【设置文件-Program.cs】
  1. var builder = WebApplication.CreateBuilder(args);
  2. // Add services to the container.
  3. builder.Services.AddControllersWithViews();
  4. //加一个session
  5. builder.Services.AddSession(options =>
  6. {
  7.     options.IdleTimeout = TimeSpan.FromMinutes(3); // 3分钟过期
  8.     options.Cookie.HttpOnly = true;
  9.     options.Cookie.IsEssential = true;
  10. });
  11. var app = builder.Build();
  12. // Configure the HTTP request pipeline.
  13. if (!app.Environment.IsDevelopment())
  14. {
  15.     app.UseExceptionHandler("/Home/Error");
  16.     // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
  17.     app.UseHsts();
  18. }
  19. app.UseHttpsRedirection();
  20. app.UseStaticFiles();
  21. app.UseRouting();
  22. app.UseAuthorization();
  23. //使用session
  24. app.UseSession();
  25. app.MapControllerRoute(
  26.     name: "default",
  27.     pattern: "{controller=Home}/{action=Index}/{id?}");
  28. app.Run();
复制代码
【实现-后端HomeController】
  1. using Microsoft.AspNetCore.Mvc;
  2. namespace WebApplication1.Controllers
  3. {
  4.     public class HomeController : Controller
  5.     {
  6.         public IActionResult Index()
  7.         {
  8.             return View();
  9.         }
  10.         [HttpPost]
  11.         public IActionResult Login(string username, string password)
  12.         {
  13.             if (username == "1" && password == "100")//省略数据库读取步骤,假设校验成功了
  14.             {
  15.                 CreateToken(HttpContext);//设置token
  16.                 return RedirectToAction("Index", "Main");//重定向到已登录界面
  17.             }
  18.             ViewBag.ErrorMessage = "登录失败,账密错误";
  19.             return View("Index");//否则重定向到本页
  20.         }
  21.         private const string TokenSessionKey = "AuthToken";
  22.         private const string TokenExpiryKey = "TokenExpiry";
  23.         public static void CreateToken(HttpContext context)//创建token
  24.         {
  25.             var token = Guid.NewGuid().ToString();//设置token
  26.             var expiry = DateTime.Now.AddMinutes(3);//设置过期日期
  27.             context.Session.SetString(TokenSessionKey, token);
  28.             context.Session.SetString(TokenExpiryKey, expiry.ToString("o")); // 使用 ISO 8601 格式
  29.         }
  30.     }
  31. }
复制代码
【实现-后端MainController】
  1. using Microsoft.AspNetCore.Mvc;
  2. namespace WebApplication1.Controllers
  3. {
  4.     public class MainController : Controller
  5.     {
  6.         public IActionResult Index()
  7.         {
  8.             if (!ValidateToken(HttpContext))//判断是否携带有效token
  9.             {
  10.                 return RedirectToAction("Index", "Home");//不是则重定向到登录界面
  11.             }
  12.             return View();//否则重定向到本页(已登录页面)
  13.         }
  14.         private const string TokenSessionKey = "AuthToken";
  15.         private const string TokenExpiryKey = "TokenExpiry";
  16.         public static bool ValidateToken(HttpContext context)
  17.         {
  18.             var token = context.Session.GetString(TokenSessionKey);//尝试获取token
  19.             var expiryString = context.Session.GetString(TokenExpiryKey);//尝试获取过期日期
  20.             if (token == null || expiryString == null)
  21.             {
  22.                 return false;//获取不到表明不是登陆状态
  23.             }
  24.             var expiry = DateTime.Parse(expiryString, null, System.Globalization.DateTimeStyles.RoundtripKind);//使用 ISO 8601 格式解析日期
  25.             return DateTime.Now <= expiry;//判断是否过期,如果过期返回false
  26.         }
  27.     }
  28. }
复制代码
【前端-Home/Index】登录界面
  1. @{
  2.     ViewData["Title"] = "Home";
  3. }
  4. <h1>Login</h1>
  5. <form method="post" action="/Home/Login">
  6.     <div>
  7.         <label for="username">Username:</label>
  8.         <input type="text" id="username" name="username" required />
  9.     </div>
  10.     <div>
  11.         <label for="password">Password:</label>
  12.         <input type="password" id="password" name="password" required />
  13.     </div>
  14.     <button type="submit">Login</button>
  15. </form>
  16. @if (ViewBag.ErrorMessage != null)
  17. {
  18.     <p style="color:red;">@ViewBag.ErrorMessage</p>
  19. }
复制代码
【小结】
1.HttpContext是当前 HTTP 哀求的上下文信息,它提供了有关哀求和相应的各种数据和服务。
2.以上demo写法不查数据库,不封装AuthService 服务类,仅为展示根本的逻辑
3.前后端交互须要对应控制器名称、控制器下的方法名称
4.利用 ISO 8601 格式(比方 "o")来存储日期时间值,是为了确保日期时间的尺度化和划一性
5.token 举行免登录时,须要后端管理或存储 token,方法有二:

  • 一是服务器或redis存储token
  • 二是利用JWT将用户信息+逾期时间嵌入 token 中,后端可以验证 token 的有用性从而获取用户id等信息,而不须要存储 token 自己。
拓展

Q:如果须要增长注销功能,应该怎样实现?
A :Main/Index加一个注销按钮,MainController扫除token和逾期时间即可
后端:
  1. // 触发注销方法
  2.     public IActionResult Logout()
  3.     {
  4.         HttpContext.Session.Remove(TokenSessionKey); // 清除 token
  5.         HttpContext.Session.Remove(TokenExpiryKey);  // 清除过期时间
  6.         return RedirectToAction("Index", "Home"); // 注销后重定向到主页
  7.     }
复制代码
前端: 
  1. <button onclick="logout()">Logout</button> <!-- 注销按钮 -->
  2. <script>
  3.     function logout() {
  4.         fetch('/Main/Logout', { // 调用后端的 Logout 方法
  5.             method: 'POST', // 使用 POST 请求
  6.             headers: {
  7.                 'Content-Type': 'application/json'
  8.             },
  9.             credentials: 'same-origin' // 确保发送会话 cookie
  10.         })
  11.         .then(response => {
  12.             if (response.ok) {
  13.                 window.location.href = '/Home/Index'; // 注销成功后重定向到主页
  14.             } else {
  15.                 console.error('Logout failed');
  16.             }
  17.         })
  18.         .catch(error => console.error('Error:', error));
  19.     }
  20. </script>
复制代码
二、JWT令牌根本demo

【需求】(同上)
        Home/Index 登录界面,校验乐成后可以登录到Main/Index ,用户登录3分钟内关闭网站,再次访问Home/Index时可以免密登录Main/Index。
【Home】
  1. using Microsoft.AspNetCore.Mvc;
  2. using Microsoft.Extensions.Configuration;
  3. using Microsoft.IdentityModel.Tokens;
  4. using System.IdentityModel.Tokens.Jwt;
  5. using System.Security.Claims;
  6. using System.Text;
  7. public class HomeController : Controller
  8. {
  9.     private readonly IConfiguration _configuration;
  10.     private readonly string _jwtSecret ;
  11.     public HomeController(IConfiguration configuration)
  12.     {
  13.         _configuration = configuration;
  14.         _jwtSecret = _configuration.GetConnectionString("DefaultConnection");
  15.     }
  16.     public IActionResult Index()
  17.     {
  18.         return View();
  19.     }
  20.     [HttpPost]
  21.     public IActionResult Index(string username, string password)
  22.     {     
  23.         if (username == "1" && password == "100")// 这里应进行实际的用户验证
  24.         {
  25.             var token = GenerateJwtToken(username);//生成JWT令牌
  26.             Response.Cookies.Append("AuthToken", token, new CookieOptions//将生成的 JWT 存储在浏览器的 Cookie 中,设置 HttpOnly 选项可以防止客户端 JavaScript 访问 Cookie,提高安全性。
  27.             {
  28.                 HttpOnly = true,
  29.                 Expires = DateTime.UtcNow.AddMinutes(3) //过期时间3分钟
  30.             });
  31.             return RedirectToAction("Index", "Main");
  32.         }
  33.         ViewBag.ErrorMessage = "登陆失败";
  34.         return View("Index");
  35.     }
  36.     private string GenerateJwtToken(string username)
  37.     {
  38.         var tokenHandler = new JwtSecurityTokenHandler();
  39.         var key = Encoding.ASCII.GetBytes(_jwtSecret);//密钥,用于签名 JWT
  40.         var tokenDescriptor = new SecurityTokenDescriptor
  41.         {
  42.             Subject = new ClaimsIdentity(new Claim[]
  43.             {
  44.                 new Claim(ClaimTypes.Name, username),//// 设置 JWT 的声明部分,包含用户信息。在这里,我们只设置了用户名
  45.                 // 你可以添加更多的声明,如角色、权限等
  46.                 new Claim(ClaimTypes.Role, "admin")  // 示例,添加用户角色
  47.             }),
  48.             Expires = DateTime.UtcNow.AddMinutes(3),//过期时间为3分钟
  49.             SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)//设置 JWT 的签名凭据。SigningCredentials 包含签名的密钥和算法,使用 HMAC-SHA256 算法进行签名
  50.         };
  51.         var token = tokenHandler.CreateToken(tokenDescriptor);
  52.         return tokenHandler.WriteToken(token);// 生成并且返回 JWT 字符串
  53.     }
  54. }
复制代码
【Main】
  1. using Microsoft.AspNetCore.Mvc;
  2. using Microsoft.IdentityModel.Tokens;
  3. using System.IdentityModel.Tokens.Jwt;
  4. using System.Security.Claims;
  5. using System.Text;
  6. public class MainController : Controller
  7. {
  8.     private readonly IConfiguration _configuration;
  9.     private readonly string _jwtSecret;
  10.     public MainController(IConfiguration configuration)
  11.     {
  12.         _configuration = configuration;
  13.         _jwtSecret = _configuration.GetConnectionString("DefaultConnection");
  14.     }
  15.     public IActionResult Index()
  16.     {
  17.         var token = Request.Cookies["AuthToken"];//从 Cookie 中读取 JWT(Key设置成了 "AuthToken",读取它的值token)。
  18.         if (ValidateToken(token))//校验token
  19.         {
  20.             return View();
  21.         }
  22.         return RedirectToAction("Index", "Home");
  23.     }
  24.     private bool ValidateToken(string token)
  25.     {
  26.         if (string.IsNullOrEmpty(token)) return false;
  27.         try
  28.         {
  29.             var tokenHandler = new JwtSecurityTokenHandler();
  30.             var key = Encoding.ASCII.GetBytes(_jwtSecret);
  31.             // 定义 TokenValidationParameters 用于验证 JWT
  32.             var validationParameters = new TokenValidationParameters
  33.             {
  34.                 ValidateIssuerSigningKey = true,
  35.                 IssuerSigningKey = new SymmetricSecurityKey(key),
  36.                 ValidateIssuer = false,
  37.                 ValidateAudience = false,
  38.                 ClockSkew = TimeSpan.Zero
  39.             };
  40.             // 验证 JWT 并返回解析后的 Token
  41.             SecurityToken validatedToken;
  42.             var principal = tokenHandler.ValidateToken(token, validationParameters, out validatedToken);
  43.             // 从 ClaimsPrincipal 对象中提取用户名
  44.             var claim = principal.FindFirst(ClaimTypes.Name);
  45.             if (claim != null)
  46.             {
  47.                 var getname = claim.Value; // 获取用户名
  48.                 return true; // 验证成功
  49.             }
  50.             return false; // 用户名未找到
  51.         }
  52.         catch
  53.         {
  54.             return false; // 验证失败
  55.         }
  56.     }
  57. }
复制代码
【Home/Index前端】(Main/Index不展示了= =)
  1. @{
  2.     ViewData["Title"] = "Home";
  3. }
  4. <h1>Login</h1>
  5. <form method="post" action="/Home">
  6.     <div>
  7.         <label for="username">Username:</label>
  8.         <input type="text" id="username" name="username" required />
  9.     </div>
  10.     <div>
  11.         <label for="password">Password:</label>
  12.         <input type="password" id="password" name="password" required />
  13.     </div>
  14.     <button type="submit">Login</button>
  15. </form>
  16. @if (ViewBag.ErrorMessage != null)
  17. {
  18.     <p style="color:red;">@ViewBag.ErrorMessage</p>
  19. }
复制代码
【appsettings.json】
  1. {
  2.   "ConnectionStrings": {
  3.     "DefaultConnection": "Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;"
  4.   },
  5.   "Logging": {
  6.     "LogLevel": {
  7.       "Default": "Information",
  8.       "Microsoft.AspNetCore": "Warning"
  9.     }
  10.   },
  11.   "AllowedHosts": "*",
  12.   "Jwt": {
  13.     "Key": "123456",
  14.     "Issuer": "MyWebApp"
  15.   }
  16. }
复制代码
【Progarm.cs】
  1. using Microsoft.AspNetCore.Authentication.JwtBearer;
  2. using Microsoft.IdentityModel.Tokens;
  3. using System.Text;
  4. var builder = WebApplication.CreateBuilder(args);
  5. // Add services to the container.
  6. builder.Services.AddControllersWithViews();
  7. //加一个session
  8. //builder.Services.AddSession(options =>
  9. //{
  10. //    options.IdleTimeout = TimeSpan.FromMinutes(3); // 3分钟过期
  11. //    options.Cookie.HttpOnly = true;
  12. //    options.Cookie.IsEssential = true;
  13. //});
  14. // JWT 相关的配置开始
  15. var jwtSettings = builder.Configuration.GetSection("Jwt");
  16. var key = Encoding.ASCII.GetBytes(jwtSettings["Key"]);
  17. // 配置JWT认证服务
  18. builder.Services.AddAuthentication(x =>
  19. {
  20.     x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
  21.     x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
  22. })
  23. .AddJwtBearer(x =>
  24. {
  25.     x.RequireHttpsMetadata = false;//设置为 false 表示不强制使用 HTTPS(在开发环境中可能是这样,但在生产环境中通常应设置为 true)。
  26.     x.SaveToken = true;//SaveToken 为 true 表示在认证成功后,将 JWT 令牌保存到 HttpContext 中。
  27.     x.TokenValidationParameters = new TokenValidationParameters
  28.     {
  29.         ValidateIssuerSigningKey = true,//true 表示验证 JWT 的签名密钥,以确保令牌未被篡改。
  30.         IssuerSigningKey = new SymmetricSecurityKey(key),//指定了用于验证签名的密钥。key 是从配置文件中读取的密钥。
  31.         ValidateIssuer = true,//true 表示验证 JWT 的发行者(Issuer),确保令牌来自预期的来源。
  32.         ValidateAudience = true,//true 表示验证受众(Audience),确保令牌是为预期的接收者颁发的。
  33.         ValidIssuer = jwtSettings["Issuer"],//指定了一个有效的发行者(Issuer)值
  34.         ValidAudience = jwtSettings["Issuer"], // 指定了一个有效的受众(Audience)值,一般是同上的
  35.         ClockSkew = TimeSpan.Zero//允许一些时间差异(例如,服务器和客户端时间不一致)的情况,但在此配置中被禁用了。
  36.     };
  37. });// JWT 相关的配置结束
  38. var app = builder.Build();
  39. // Configure the HTTP request pipeline.
  40. if (!app.Environment.IsDevelopment())
  41. {
  42.     app.UseExceptionHandler("/Home/Error");
  43.     // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
  44.     app.UseHsts();
  45. }
  46. app.UseHttpsRedirection();
  47. app.UseStaticFiles();
  48. app.UseRouting();
  49. app.UseAuthentication(); // 确保认证在授权之前使用
  50. app.UseAuthorization();
  51. //使用session
  52. //app.UseSession();
  53. app.MapControllerRoute(
  54.     name: "default",
  55.     pattern: "{controller=Home}/{action=Index}/{id?}");
  56. app.Run();
复制代码
 
 

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表