663 lines
27 KiB
C#
663 lines
27 KiB
C#
using DocumentFormat.OpenXml.Office2010.Excel;
|
||
using Lazy.Captcha.Core;
|
||
using Microsoft.AspNetCore.Authentication;
|
||
using Microsoft.AspNetCore.Http;
|
||
using Microsoft.AspNetCore.Identity;
|
||
using Newtonsoft.Json;
|
||
using Newtonsoft.Json.Linq;
|
||
using NPOI.SS.Formula.Functions;
|
||
using System.Security.Claims;
|
||
using YLErp.Configuration;
|
||
|
||
namespace YLErp.Web.Controllers
|
||
{
|
||
public class AccountController : Controller
|
||
{
|
||
private const string _auth_login = "_auth_login_";
|
||
|
||
private readonly IHttpClientFactory _httpClientFactory;
|
||
private readonly ICaptcha _captcha;
|
||
|
||
public AccountController(IHttpClientFactory httpClientFactory, ICaptcha captcha)
|
||
{
|
||
_httpClientFactory = httpClientFactory;
|
||
_captcha = captcha;
|
||
}
|
||
|
||
//---------------------------------------
|
||
// 安全逻辑:
|
||
// 每个浏览器客户端应该有一个guid确定其唯一性
|
||
// 如果没有guid则在cookie中设置并需要输入验证码
|
||
// 如果有guid,则根据服务端缓存判断此浏览器是否上次登录失败
|
||
// 如果上次登录失败,则显示验证码输入,否则不需要
|
||
//---------------------------------------
|
||
|
||
public ActionResult Login(bool skipSso = false)
|
||
{
|
||
var logger = LogFactory.GetLogger<AccountController>();
|
||
var remoteIp = HttpContext.Connection.RemoteIpAddress?.ToString();
|
||
|
||
// 记录所有 Cookie
|
||
var allCookies = Request.Cookies.Select(c => $"{c.Key}={(c.Value?.Length > 10 ? c.Value?.Substring(0, 10) + "..." : c.Value)}").ToList();
|
||
var hasAccessToken = Request.Cookies.ContainsKey("Access-Token");
|
||
logger.Info($"[登录页面] 访问登录页,IP: {remoteIp}, skipSso: {skipSso}, HasAccessToken: {hasAccessToken}, Cookies: [{string.Join(", ", allCookies)}]");
|
||
|
||
var keys = Request.Cookies.Keys.ToArray();
|
||
logger.Info($"[登录页面] 清除 {keys.Length} 个 Cookie(保留 {_auth_login})");
|
||
|
||
foreach (var key in keys)
|
||
{
|
||
if (key != _auth_login)
|
||
{
|
||
Response.Cookies.Delete(key);
|
||
logger.Info($"[登录页面] 删除 Cookie: {key}");
|
||
}
|
||
}
|
||
|
||
// 检查天风SSO
|
||
if (SsoLoginConfig.SSO_Enable && PS.Config.Company == CompanyEnum.天风)
|
||
{
|
||
logger.Info($"[登录页面] 天风SSO已启用,跳转到天风登录页");
|
||
return View("TianFengLogin");
|
||
}
|
||
|
||
// 检查是否禁用密码登录
|
||
var disablePasswordLogin = PS.Config.ErpElement.DisablePasswordLogin;
|
||
var strictAuthorize = PS.Config.ErpElement.StrictAuthorize;
|
||
logger.Info($"[登录页面] 配置检查 - DisablePasswordLogin: {disablePasswordLogin}, StrictAuthorize: {strictAuthorize}, Company: {PS.Config.Company}");
|
||
|
||
// 注意:DisablePasswordLogin 的逻辑在 Login.cshtml 视图中处理
|
||
// 这里不再直接跳转,而是显示登录页,由页面决定显示什么内容
|
||
|
||
return LoginError(null);
|
||
}
|
||
|
||
public ActionResult Login2()
|
||
{
|
||
return Login(true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 登录错误
|
||
/// </summary>
|
||
private ActionResult LoginError(string errorMessage, Exception ex = null)
|
||
{
|
||
var strictAuthorize = PS.Config.ErpElement.StrictAuthorize;
|
||
|
||
var model = new LogOnModel
|
||
{
|
||
ErrorMessage = errorMessage,
|
||
NeedCaptcha = strictAuthorize,
|
||
Exception = ex,
|
||
LoadTime = DateTime.Now
|
||
};
|
||
|
||
if (strictAuthorize)
|
||
{
|
||
var hasError = !string.IsNullOrEmpty(errorMessage);
|
||
Request.Cookies.TryGetValue(_auth_login, out var guid);
|
||
if (string.IsNullOrEmpty(guid) || guid.Length < 30)
|
||
{
|
||
guid = Guid.NewGuid().ToString("N");
|
||
Response.Cookies.Append(_auth_login, guid, new CookieOptions
|
||
{
|
||
HttpOnly = true,
|
||
Expires = DateTimeOffset.Now.AddHours(1)
|
||
});
|
||
}
|
||
|
||
Server.CacheProvider.Set(_auth_login + guid, hasError ? "##" : "#", TimeSpan.FromMinutes(20));
|
||
|
||
var sid = guid + "#" + model.LoadTime.ToString("yyyyMMddHHmmss") + (model.NeedCaptcha ? "#1" : "#0");
|
||
|
||
model.SID = DataProtectHelper.Encrypt(sid);
|
||
}
|
||
|
||
return View(nameof(Login), model);
|
||
}
|
||
|
||
[HttpPost, ResponseCache(NoStore = true)]
|
||
public async Task<IActionResult> LoginHandle(LogOnModel model)
|
||
{
|
||
var logger = LogFactory.GetLogger<AccountController>();
|
||
var hasToken = Request.Cookies.ContainsKey("Access-Token");
|
||
logger.Info($"[登录处理] 收到登录请求 - UserName: {model?.UserName}, HasAccessToken: {hasToken}");
|
||
|
||
if (string.IsNullOrWhiteSpace(model?.UserName) || string.IsNullOrWhiteSpace(model?.Password))
|
||
{
|
||
logger.Info("[登录处理] 用户名或密码为空");
|
||
return LoginError("用户名和密码必须填写");
|
||
}
|
||
|
||
if (model.LoadTime.Year < 2000)
|
||
{
|
||
return LoginError("登录失败,非正常请求");
|
||
}
|
||
if (PS.Config.ErpElement.StrictAuthorize)
|
||
{
|
||
if (string.IsNullOrEmpty(model.SID) || DateTime.Now > model.LoadTime.AddMinutes(20))
|
||
{
|
||
return LoginError("请求已过期,请重新登录");
|
||
}
|
||
|
||
Request.Cookies.TryGetValue(_auth_login, out var guid);
|
||
|
||
if (string.IsNullOrEmpty(guid))
|
||
{
|
||
return LoginError("请求无效,请重新登录");
|
||
}
|
||
|
||
try
|
||
{
|
||
var sids = DataProtectHelper.Decrypt(model.SID).Split('#');
|
||
|
||
if (sids.Length < 3 || sids[0] != guid )
|
||
{
|
||
return LoginError("请求参数失效,请重新登录");
|
||
}
|
||
|
||
if (sids[2] == "1")
|
||
{
|
||
var key = _auth_login + guid;
|
||
if (!_captcha.Validate(key, model.CaptchaCode))
|
||
{
|
||
return LoginError("验证码错误");
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return LoginError("验证出错", ex);
|
||
}
|
||
}
|
||
|
||
try
|
||
{
|
||
model.UserName = Decode(model.UserName);
|
||
model.Password = Decode(model.Password);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return LoginError("验证出错", ex);
|
||
}
|
||
var errorNumStr = Server.CacheProvider.Get($"login:user:error:{model.UserName.ToLower()}")?.ToString();
|
||
var errorNum = string.IsNullOrEmpty(errorNumStr) ? 0 : Convert.ToInt32(errorNumStr);
|
||
if (errorNum >= PS.Config.ErpElement.PasswordErrorLimit && PS.Config.ErpElement.StrictAuthorize)
|
||
{
|
||
return LoginError("账户已被锁定,请稍后再试");
|
||
}
|
||
SystemUser user = null;
|
||
|
||
if (SsoLoginConfig.SSO_Enable)
|
||
{
|
||
switch (model.UserName.ToLowerInvariant())
|
||
{
|
||
case "admin":
|
||
case "supera": break;
|
||
default:
|
||
if (PS.Config.Company == CompanyEnum.天风)
|
||
{
|
||
return LoginError("非管理员账户,请刷新页面后使用普通用户登录方式");
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (user == null)
|
||
{
|
||
var result = SystemUser.CheckUser(model.UserName, model.Password, out user);
|
||
|
||
if (result != UserCheckResult.验证通过)
|
||
{
|
||
var errorResult = result.ToString();
|
||
if (PS.Config.ErpElement.StrictAuthorize)
|
||
{
|
||
errorNum++;
|
||
var passwordErrorLimit = PS.Config.ErpElement.PasswordErrorLimit;
|
||
if (errorNum < passwordErrorLimit)
|
||
{
|
||
errorResult = $"{errorResult},您还有{passwordErrorLimit - errorNum}次机会登录尝试";
|
||
}
|
||
else
|
||
{
|
||
var lockMinutes = PS.Config.ErpElement.PasswordErrorLockMinutes;
|
||
errorResult = $"{errorResult},账号已被锁定,请{lockMinutes}分钟后再尝试!";
|
||
}
|
||
Server.CacheProvider.Set($"login:user:error:{model.UserName.ToLower()}", errorNum, TimeSpan.FromMinutes(PS.Config.ErpElement.PasswordErrorLockMinutes));
|
||
}
|
||
return LoginError(errorResult);
|
||
}
|
||
|
||
if (user == null || user.Id < 1)
|
||
{
|
||
return LoginError("验证失败," + result.ToString());
|
||
}
|
||
}
|
||
|
||
var userToken = Guid.NewGuid().ToString("N");
|
||
|
||
using (var db = DbContextFactory.GetErpBaseContext())
|
||
{
|
||
user = db.SystemUsers.Find(user.Id);
|
||
user.UserToken = userToken;
|
||
db.SystemUserLoginfo.Add(new SystemUserLoginfo
|
||
{
|
||
IPAddress = HttpContext.Connection.RemoteIpAddress?.ToString(),
|
||
LogTime = DateTime.Now,
|
||
LogType = "登入",
|
||
UserId = user.Id,
|
||
UserName = user.Name,
|
||
LoginName = model.UserName,
|
||
MACAddress = "",
|
||
LoadTime = model.LoadTime
|
||
});
|
||
db.SaveChanges();
|
||
}
|
||
|
||
//保存到cookie
|
||
Server.CacheProvider.Set($"login:user:error:{model.UserName.ToLower()}", 0, TimeSpan.FromMinutes(PS.Config.ErpElement.PasswordErrorLockMinutes));
|
||
var identity = UserManager.CreateIdentity(user.Id.ToString(), user.Name, userToken);
|
||
|
||
await HttpContext.SignInAsync(AuthHelper.CookieAuthType, new ClaimsPrincipal(identity));
|
||
|
||
// 先删除可能存在的旧Token(避免黑名单影响)
|
||
Response.Cookies.Delete("Access-Token");
|
||
Response.Cookies.Delete("Access-Token-Encrypt");
|
||
|
||
var jwtToken = AuthHelper.CreateJwtToken2(identity);
|
||
Response.Cookies.Append("Access-Token", jwtToken, new CookieOptions
|
||
{
|
||
MaxAge = TimeSpan.FromSeconds(AuthHelper.ExpireInSeconds)
|
||
});
|
||
Response.Cookies.Append("Access-Token-Encrypt", DataProtectHelper.Encrypt(jwtToken));
|
||
//保存到缓存
|
||
var userInfo = UserInfo.FromDbUser(user);
|
||
Server.CacheProvider.Set("loginUser^" + user.Id, userInfo, TimeSpan.FromMinutes(30));
|
||
|
||
if (!PasswordValidator.Validate(model.Password))
|
||
{
|
||
Server.CacheProvider.Set("简单密码" + user.Id, "是", TimeSpan.FromMinutes(60));
|
||
}
|
||
|
||
return RedirectToAction("Index", "Home", new { g = Guid.NewGuid() });
|
||
}
|
||
|
||
public ActionResult LogOut()
|
||
{
|
||
var logger = LogFactory.GetLogger<AccountController>();
|
||
var userId = User.GetUserId();
|
||
var loginName = User.GetUserName();
|
||
var remoteIp = HttpContext.Connection.RemoteIpAddress?.ToString();
|
||
|
||
// 记录所有 Cookie
|
||
var allCookies = Request.Cookies.Select(c => $"{c.Key}={c.Value?.Substring(0, Math.Min(10, c.Value?.Length ?? 0))}...").ToList();
|
||
logger.Info($"[退出登录] 用户请求退出 - UserId: {userId}, LoginName: {loginName}, IP: {remoteIp}, Cookies: [{string.Join(", ", allCookies)}]");
|
||
|
||
if (userId > 0)
|
||
{
|
||
Server.CacheProvider.Remove("loginUser^" + userId);
|
||
try
|
||
{
|
||
using (var db = Modules.DbContextFactory.GetErpBaseContext())
|
||
{
|
||
var user = db.SystemUsers.Find(userId);
|
||
if (user != null)
|
||
{
|
||
user.UserToken = string.Empty;
|
||
loginName = user.LoginName;
|
||
}
|
||
db.SystemUserLoginfo.Add(new SystemUserLoginfo
|
||
{
|
||
IPAddress = remoteIp,
|
||
LogTime = DateTime.Now,
|
||
LogType = "登出",
|
||
UserId = userId,
|
||
UserName = user?.Name ?? User.GetUserName(),
|
||
MACAddress = string.Empty
|
||
});
|
||
db.SaveChanges();
|
||
logger.Info($"[退出登录] 用户退出记录已保存 - UserId: {userId}, LoginName: {loginName}");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
logger.Error($"[退出登录] 保存退出记录失败 - UserId: {userId}", ex);
|
||
}
|
||
}
|
||
|
||
HttpContext.SignOutAsync(IdentityConstants.ApplicationScheme);
|
||
logger.Info($"[退出登录] SignOutAsync 已调用");
|
||
|
||
// 先将当前 JWT Token 加入黑名单(使其立即失效),然后再删除 Cookie
|
||
string accessToken = null;
|
||
if (Request.Cookies.TryGetValue("Access-Token", out accessToken) && !string.IsNullOrEmpty(accessToken))
|
||
{
|
||
try
|
||
{
|
||
var tokenHandler = new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler();
|
||
var jwtToken = tokenHandler.ReadJwtToken(accessToken);
|
||
var jti = jwtToken.Claims.FirstOrDefault(c => c.Type == "jti")?.Value ?? accessToken.Substring(0, 32);
|
||
var expiry = jwtToken.ValidTo;
|
||
var ttl = expiry - DateTime.UtcNow;
|
||
|
||
if (ttl.TotalSeconds > 0)
|
||
{
|
||
// 将 Token 加入黑名单,过期时间与 Token 过期时间相同
|
||
Server.CacheProvider.Set($"token_blacklist:{jti}", userId.ToString(), ttl);
|
||
logger.Info($"[退出登录] Token 已加入黑名单 - JTI: {jti}, 过期时间: {expiry:yyyy-MM-dd HH:mm:ss}");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
logger.Error($"[退出登录] Token 加入黑名单失败", ex);
|
||
}
|
||
}
|
||
|
||
// 清除所有 Cookie(确保旧Token不会带到登录页面)
|
||
var keys = Request.Cookies.Keys.ToArray();
|
||
foreach (var key in keys)
|
||
{
|
||
Response.Cookies.Delete(key);
|
||
}
|
||
logger.Info($"[退出登录] 所有 Cookie 已清除,共 {keys.Length} 个");
|
||
|
||
if (SsoLoginConfig.SSO_Enable)
|
||
{
|
||
switch (loginName?.ToLowerInvariant())
|
||
{
|
||
case "admin":
|
||
case "supera": break;
|
||
default:
|
||
if (PS.Config.Company == CompanyEnum.天风)
|
||
{
|
||
return View("TianFengLogout");
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
logger.Info($"[退出登录] 准备重定向到登录页,清除的Cookie数量: {keys.Length}");
|
||
|
||
// 添加响应头,确保浏览器清除Cookie
|
||
Response.Headers.Add("Cache-Control", "no-cache, no-store, must-revalidate");
|
||
Response.Headers.Add("Pragma", "no-cache");
|
||
Response.Headers.Add("Expires", "0");
|
||
|
||
return RedirectToAction("Login");
|
||
}
|
||
|
||
public ActionResult Captcha()
|
||
{
|
||
Request.Cookies.TryGetValue(_auth_login, out var guid);
|
||
|
||
if (string.IsNullOrEmpty(guid) || guid.Length < 30)
|
||
{
|
||
return StatusCode((int)System.Net.HttpStatusCode.InternalServerError, "cookie无效");
|
||
}
|
||
|
||
var key = _auth_login + guid;
|
||
var value = Server.CacheProvider.Get(key)?.ToString();
|
||
|
||
if (value == null)
|
||
{
|
||
return StatusCode((int)System.Net.HttpStatusCode.InternalServerError, "页面停留超时");
|
||
}
|
||
|
||
var info = _captcha.Generate(key);
|
||
// 有多处验证码且过期时间不一样,可传第二个参数覆盖默认配置。
|
||
//var info = _captcha.Generate(id,120);
|
||
var stream = new MemoryStream(info.Bytes);
|
||
return File(stream, "image/jpeg");
|
||
}
|
||
|
||
private static string Decode(string btoa)
|
||
{
|
||
var mod4 = btoa.Length % 4;
|
||
if (mod4 > 0)
|
||
{
|
||
btoa += new string('=', 4 - mod4);
|
||
}
|
||
var data = Convert.FromBase64String(btoa);
|
||
var strs = System.Text.Encoding.ASCII.GetString(data).Split(',');
|
||
var arr = new char[strs.Length];
|
||
for (var i = 0; i < strs.Length; i++)
|
||
{
|
||
arr[i] = (char)int.Parse(strs[i]);
|
||
}
|
||
return new string(arr);
|
||
}
|
||
|
||
#region----天风证券单点登录----
|
||
|
||
/// <summary>
|
||
/// 天风证券单点登录
|
||
/// </summary>
|
||
public async Task<ActionResult> TianFengSSO()
|
||
{
|
||
var serviceUrl = Url.Action("TianFengSSO", "account", null, Request.Scheme);
|
||
var model = new SsoLogOnModel
|
||
{
|
||
SsoUrl = TianFengSSOHandler.GetSsoLoginUrl(serviceUrl)
|
||
};
|
||
|
||
try
|
||
{
|
||
var ticket = Request.Query["ticket"];
|
||
if (string.IsNullOrWhiteSpace(ticket))
|
||
{
|
||
return View(model.SetError("缺少单点登录令牌!"));
|
||
}
|
||
|
||
var userName = await new TianFengSSOHandler(_httpClientFactory).ValidateAsync(ticket, serviceUrl);
|
||
var userToken = Guid.NewGuid().ToString("N");
|
||
|
||
SystemUser user = null;
|
||
using (var db = Modules.DbContextFactory.GetErpBaseContext())
|
||
{
|
||
user = db.SystemUsers.FirstOrDefault(n => n.LoginName == userName);
|
||
if (user == null)
|
||
{
|
||
return View(model.SetError("找不到系统用户:" + userName));
|
||
}
|
||
user.UserToken = userToken;
|
||
db.SystemUserLoginfo.Add(new SystemUserLoginfo
|
||
{
|
||
IPAddress = HttpContext.Connection.RemoteIpAddress.ToString(),
|
||
LogTime = DateTime.Now,
|
||
LogType = "登入",
|
||
UserId = user.Id,
|
||
UserName = user.Name,
|
||
LoginName = user.LoginName,
|
||
MACAddress = "",
|
||
LoadTime = DateTime.Now
|
||
});
|
||
db.SaveChanges();
|
||
}
|
||
|
||
//保存到cookie
|
||
var identity = UserManager.CreateIdentity(user.Id.ToString(), user.Name, userToken);
|
||
|
||
await HttpContext.SignInAsync(AuthHelper.CookieAuthType, new ClaimsPrincipal(identity));
|
||
|
||
var jwtToken = AuthHelper.CreateJwtToken(identity);
|
||
|
||
Response.Cookies.Append("Access-Token", jwtToken, new CookieOptions
|
||
{
|
||
Domain = Request.Host.Host,
|
||
MaxAge = TimeSpan.FromSeconds(AuthHelper.ExpireInSeconds)
|
||
});
|
||
|
||
//保存到缓存
|
||
var userInfo = UserInfo.FromDbUser(user);
|
||
|
||
Server.CacheProvider.Set("loginUser^" + user.Id, userInfo, TimeSpan.FromMinutes(30));
|
||
|
||
return RedirectToAction("Index", "Home");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return View(model.SetError("单点登录出错:" + ex.ToString()));
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region----通用单点登录回调----
|
||
|
||
/// <summary>
|
||
/// 通用单点登录回调处理
|
||
/// </summary>
|
||
public async Task<ActionResult> Callback()
|
||
{
|
||
try
|
||
{
|
||
var code = Request.Query["code"];
|
||
var state = Request.Query["state"];
|
||
|
||
if (string.IsNullOrWhiteSpace(code))
|
||
{
|
||
return Content("缺少授权码(code参数)");
|
||
}
|
||
|
||
// 调用SSO服务器接口获取用户信息
|
||
var getUserUrl = GeneralSSOConfig.GetUserUrl;
|
||
if (string.IsNullOrWhiteSpace(getUserUrl))
|
||
{
|
||
return Content("获取用户信息接口地址未配置");
|
||
}
|
||
|
||
var httpClient = _httpClientFactory.CreateClient();
|
||
var response = await httpClient.GetStringAsync($"{getUserUrl}?code={code}");
|
||
|
||
if (string.IsNullOrWhiteSpace(response))
|
||
{
|
||
return Content("获取用户信息失败");
|
||
}
|
||
|
||
// 解析返回的用户信息JSON
|
||
var userInfoData = JsonConvert.DeserializeObject<Dictionary<string, object>>(response);
|
||
if (userInfoData.ContainsKey("data"))
|
||
{
|
||
var dataValue = userInfoData["data"];
|
||
Dictionary<string, object> data = null;
|
||
|
||
try
|
||
{
|
||
// 尝试直接解析为字典
|
||
if (dataValue is JToken jToken)
|
||
{
|
||
data = jToken.ToObject<Dictionary<string, object>>();
|
||
}
|
||
else if (dataValue is Dictionary<string, object> dataDict)
|
||
{
|
||
data = dataDict;
|
||
}
|
||
else if (dataValue is string dataString)
|
||
{
|
||
// 如果是字符串,尝试解析为JSON
|
||
data = JsonConvert.DeserializeObject<Dictionary<string, object>>(dataString);
|
||
}
|
||
else
|
||
{
|
||
// 尝试将任何类型转换为字符串再解析
|
||
var stringValue = dataValue?.ToString();
|
||
if (!string.IsNullOrEmpty(stringValue))
|
||
{
|
||
data = JsonConvert.DeserializeObject<Dictionary<string, object>>(stringValue);
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return Content("解析data字段失败: " + ex.Message);
|
||
}
|
||
|
||
if (data == null)
|
||
{
|
||
return Content("data字段解析失败");
|
||
}
|
||
|
||
if (data.ContainsKey("user_id"))
|
||
{
|
||
var userId = data["user_id"]?.ToString()?.Trim();
|
||
if (string.IsNullOrEmpty(userId))
|
||
{
|
||
return Content("userId字段为空");
|
||
}
|
||
|
||
var userToken = Guid.NewGuid().ToString("N");
|
||
SystemUser user = null;
|
||
|
||
using (var db = Modules.DbContextFactory.GetErpBaseContext())
|
||
{
|
||
user = db.SystemUsers.FirstOrDefault(n => n.LoginName == userId);
|
||
if (user == null)
|
||
{
|
||
return Content("找不到系统用户:" + userId);
|
||
}
|
||
if (user.State != (int)UserState.Enabled)
|
||
{
|
||
return Content("系统用户:" + userId + "处于禁用状态");
|
||
}
|
||
user.UserToken = userToken;
|
||
db.SystemUserLoginfo.Add(new SystemUserLoginfo
|
||
{
|
||
IPAddress = HttpContext.Connection.RemoteIpAddress.ToString(),
|
||
LogTime = DateTime.Now,
|
||
LogType = "登入",
|
||
UserId = user.Id,
|
||
UserName = user.Name,
|
||
LoginName = user.LoginName,
|
||
MACAddress = "",
|
||
LoadTime = DateTime.Now
|
||
});
|
||
db.SaveChanges();
|
||
}
|
||
|
||
var identity = UserManager.CreateIdentity(user.Id.ToString(), user.Name, userToken);
|
||
|
||
await HttpContext.SignInAsync(AuthHelper.CookieAuthType, new ClaimsPrincipal(identity));
|
||
|
||
var jwtToken = AuthHelper.CreateJwtToken(identity);
|
||
|
||
Response.Cookies.Append("Access-Token", jwtToken, new CookieOptions
|
||
{
|
||
Domain = Request.Host.Host,
|
||
MaxAge = TimeSpan.FromSeconds(AuthHelper.ExpireInSeconds)
|
||
});
|
||
|
||
Response.Cookies.Append("Access-Token-Encrypt", DataProtectHelper.Encrypt(jwtToken), new CookieOptions
|
||
{
|
||
Domain = Request.Host.Host,
|
||
MaxAge = TimeSpan.FromSeconds(AuthHelper.ExpireInSeconds)
|
||
});
|
||
|
||
// 打印日志
|
||
var logger = LogFactory.GetLogger<AccountController>();
|
||
logger.Info($"用户 {user.LoginName} 登录成功,生成JWT令牌");
|
||
|
||
var userDbInfo = UserInfo.FromDbUser(user);
|
||
|
||
Server.CacheProvider.Set("loginUser^" + user.Id, userDbInfo, TimeSpan.FromMinutes(30));
|
||
|
||
return RedirectToAction("Index", "Home");
|
||
}
|
||
else
|
||
{
|
||
return Content("响应中缺少fullname字段");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
return Content("响应中缺少data字段");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return Content("单点登录出错:" + ex.ToString());
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
} |