session id是服务器首次与浏览器创建连接时,生成的id值,存入浏览器端cookie中,值加密的,下次请求时,浏览器自动带上session值发送给服务器,服务器根据cookie中存的session id值提取服务器存的用户信息,
基于上面的原理,在服务器集群中,如果服务器甲与浏览器建立了连接,则有个session id,如果下一个请求被负载均衡器转发给服务器乙处理,则服务器乙与浏览器也会建立一个新的session id,因为session的cookie名称相同,所以导致session id会被刷新,导致一直都没有登录,
登录成功后,将唯一凭据,比如【用户id+“#”+客户端ip+“#”+当前时间】,加密后的值作为cookie的值返回给浏览器,作为登录凭据,服务器根据此用户id作为缓存key,缓存值就存用户信息。
此时的cookie是可以在集群中传输的,服务器可以正常的提取到登录用户的id。
///
///ajax, 登录处理
///
/// 账号
/// 密码
///
public async Task<IActionResult> LoginDo(string account, string password)
{
//GetCustumerIP 获取当前客户端ip
var result = await userBLL.DoLoginAsync(account, password, null, GetCustumerIP);
if (result.Code == 200)
{
var _cookieOptions = new CookieOptions()
{
//Expires = DateTime.Now.AddMinutes(30),
HttpOnly = true, /* 防御XSS攻击 */
};
//将用户id存入cookie
//解决nginx反向代理cookie问题;
string loginAuthTxt = result.Data.Authorize_user_id.ToString() + "#" + GetCustumerIP + "#" + DateTime.Now.AddHours(12).ToString("yyyy-MM-dd HH:mm:ss.fff");
//AES加密
string encryUserId = AesHelpter.AESEncryptToHex(loginAuthTxt);
Response.Cookies.Append(CacheKeyConfig.CookieName_loginAuth, encryUserId, _cookieOptions);
}
return Json(new Model.Result( result.Msg, result.Code));
}
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Policy;
using Microsoft.AspNetCore.Routing;
using Web_rongmeiti_sys.Handler;
using Web_rongmeiti_sys.Model;
using Newtonsoft.Json.Linq;
using Microsoft.JSInterop.Infrastructure;
namespace Web_rongmeiti_sys
{
/*
IAsyncAuthorizationFilter
IAuthorizationFilter
AuthorizeAttribute
*/
///
/// 登录验证,权限验证,action过滤。FunId为空只验证登录,不验证权限
///
public class LoginFilter : Attribute, IAsyncAuthorizationFilter
{
public LoginFilter()
{
}
public LoginFilter(string funId)
{
FunId = funId;
}
///
/// 方法标识id
///
private string FunId { get; set; }
public Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
获取登录用户id值,修改时间:2023-8-2 09:37:10
string? userId_encry = string.Empty;
context.HttpContext.Request.Cookies.TryGetValue(CacheKeyConfig.CookieName_loginAuth, out userId_encry);
bool isAjax = MyExceptionFilter.IsAjax(context.HttpContext.Request);
if (string.IsNullOrWhiteSpace(userId_encry))
{
//没有登录,去登录
goto To_login;
}
//验证cookie值是否有效?
try
{
string descValue = AesHelpter.AESDecryptByHex(userId_encry);
if (descValue.IndexOf("#") == -1)
{
goto To_login;
}
string tokenIP = descValue.Split("#")[1];
if (!tokenIP.Equals(GetCustumerIP(context)))
{
goto To_login;
}
string expireTimeStr = descValue.Split("#")[2];
if (!DateTime.TryParse(expireTimeStr, out DateTime expireTime) ||
expireTime <= DateTime.Now)
{
goto To_login;
}
}
catch (Exception)
{
goto To_login;
}
if (string.IsNullOrWhiteSpace(FunId))
{
return Task.CompletedTask;
}
To_login:
if (isAjax)
{
//无权访问
//context.Result = new UnauthorizedResult();
context.Result = new JsonResult(new { Code = 500, Msg = "登录失效,请重新登录" })
{
StatusCode = StatusCodes.Status401Unauthorized
};
return Task.CompletedTask;
}
//没有登录,去登录
context.Result = new RedirectResult("/user/Login");
//删除cookie
context.HttpContext.Response.Cookies.Delete(CacheKeyConfig.CookieName_loginAuth);
return Task.CompletedTask;
}
///
/// 获取访问者ip
///
public string GetCustumerIP(AuthorizationFilterContext context)
{
var request = context.HttpContext.Request;
Microsoft.Extensions.Primitives.StringValues ip;
//X-Real-IP,nginx代理传输的客户端真实ip,添加时间:2023-8-2 09:42:03
if (request.Headers.TryGetValue("X-Real-IP", out ip))
{
return ip.ToString();
}
//获取访问者ip
return context.HttpContext.Connection.RemoteIpAddress.ToString();
}
}
}
public class HomeController : BaseController
{
[LoginFilter]
public ActionResult Index()
{
//当前登录用户
var userLogin=CurrentLoginUser;
return View();
}
}
using Microsoft.AspNetCore.Mvc;
using Web_rongmeiti_sys.Business_Interface;
using Web_rongmeiti_sys.DAL_Interface;
using Web_rongmeiti_sys.Model;
namespace Web_rongmeiti_sys.Controllers
{
///
/// 基础,控制器,
///
/// 创建时间:2023-6-26 15:44:17
public class BaseController : Controller
{
///
/// 获取访问者ip
///
public string GetCustumerIP
{
get
{
Microsoft.Extensions.Primitives.StringValues ip;
//X-Real-IP,nginx代理传输的客户端真实ip,添加时间:2023-8-2 09:42:03
if (Request.Headers.TryGetValue("X-Real-IP", out ip))
{
return ip.ToString();
}
//获取访问者ip
return HttpContext.Connection.RemoteIpAddress.ToString();
}
}
///
/// 当前登录用户
///
public Authorize_user CurrentLoginUser
{
get
{
try
{
获取登录用户id值, 2023-8-2 09:42:53
string? userId_encry = string.Empty;
Request.Cookies.TryGetValue(CacheKeyConfig.CookieName_loginAuth, out userId_encry);
if (string.IsNullOrEmpty(userId_encry))
{
throw new Exception("登录失效,userId_encry ");
}
string desc = AesHelpter.AESDecryptByHex(userId_encry);
string userId = desc.Split("#")[0];
Authorize_user? user = System.Runtime.Caching.MemoryCache.Default.Get(userId) as Authorize_user;
if (user == null)
{
IUserBusiness userBusiness = ServicesHelpter.GetService<IUserBusiness>();
long userId2 = long.Parse(userId);
user = userBusiness.GetAsync(userId2).Result;
//登录成功,缓存用户,缓存12小时
System.Runtime.Caching.MemoryCache.Default.Set(userId, user, DateTimeOffset.Now.AddSeconds(43200));
}
return user;
}
catch (Exception ex)
{
throw new Exception("获取登录用户异常,", ex);
}
}
}
}
}