1161 lines
48 KiB
C#
1161 lines
48 KiB
C#
using JNPF.Common.Const;
|
|
using JNPF.Common.Captcha.General;
|
|
using JNPF.Common.Core.Manager;
|
|
using JNPF.Common.Dtos.OAuth;
|
|
using JNPF.Common.Enums;
|
|
using JNPF.Common.Extension;
|
|
using JNPF.Common.Manager;
|
|
using JNPF.Common.Models.User;
|
|
using JNPF.Common.Net;
|
|
using JNPF.Common.Security;
|
|
using JNPF.DataEncryption;
|
|
using JNPF.DependencyInjection;
|
|
using JNPF.DynamicApiController;
|
|
using JNPF.EventBus;
|
|
using JNPF.EventHandler;
|
|
using JNPF.FriendlyException;
|
|
using JNPF.Logging.Attributes;
|
|
using JNPF.OAuth.Dto;
|
|
using JNPF.OAuth.Model;
|
|
using JNPF.RemoteRequest.Extensions;
|
|
using JNPF.Systems.Entitys.Enum;
|
|
using JNPF.Systems.Entitys.Model.SysConfig;
|
|
using JNPF.Systems.Entitys.Permission;
|
|
using JNPF.Systems.Entitys.System;
|
|
using JNPF.Systems.Interfaces.System;
|
|
using JNPF.UnifyResult;
|
|
using Mapster;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.Extensions.Options;
|
|
using SqlSugar;
|
|
using JNPF.Systems.Entitys.Dto.Module;
|
|
using JNPF.Systems.Entitys.Model.Permission.SocialsUser;
|
|
using JNPF.Systems.Interfaces.Permission;
|
|
using JNPF.Extras.CollectiveOAuth.Models;
|
|
using JNPF.Common.Models;
|
|
|
|
namespace JNPF.OAuth;
|
|
|
|
/// <summary>
|
|
/// 业务实现:身份认证模块 .
|
|
/// </summary>
|
|
[ApiDescriptionSettings(Tag = "OAuth", Name = "OAuth", Order = 160)]
|
|
[Route("api/[controller]")]
|
|
public class OAuthService : IDynamicApiController, ITransient
|
|
{
|
|
/// <summary>
|
|
/// 用户仓储.
|
|
/// </summary>
|
|
private readonly ISqlSugarRepository<UserEntity> _userRepository;
|
|
|
|
/// <summary>
|
|
/// 功能模块.
|
|
/// </summary>
|
|
private readonly IModuleService _moduleService;
|
|
|
|
/// <summary>
|
|
/// 功能按钮.
|
|
/// </summary>
|
|
private readonly IModuleButtonService _moduleButtonService;
|
|
|
|
/// <summary>
|
|
/// 功能列.
|
|
/// </summary>
|
|
private readonly IModuleColumnService _columnService;
|
|
|
|
/// <summary>
|
|
/// 功能数据权限计划.
|
|
/// </summary>
|
|
private readonly IModuleDataAuthorizeSchemeService _moduleDataAuthorizeSchemeService;
|
|
|
|
/// <summary>
|
|
/// 功能表单.
|
|
/// </summary>
|
|
private readonly IModuleFormService _formService;
|
|
|
|
/// <summary>
|
|
/// 系统配置.
|
|
/// </summary>
|
|
private readonly ISysConfigService _sysConfigService;
|
|
|
|
/// <summary>
|
|
/// 验证码处理程序.
|
|
/// </summary>
|
|
private readonly IGeneralCaptcha _captchaHandler;
|
|
|
|
/// <summary>
|
|
/// 第三方登录.
|
|
/// </summary>
|
|
private readonly ISocialsUserService _socialsUserService;
|
|
|
|
/// <summary>
|
|
/// 数据库配置选项.
|
|
/// </summary>
|
|
private readonly ConnectionStringsOptions _connectionStrings;
|
|
|
|
/// <summary>
|
|
/// 多租户配置选项.
|
|
/// </summary>
|
|
private readonly TenantOptions _tenant;
|
|
|
|
/// <summary>
|
|
/// Http上下文.
|
|
/// </summary>
|
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
|
|
|
/// <summary>
|
|
/// 缓存管理.
|
|
/// </summary>
|
|
private readonly ICacheManager _cacheManager;
|
|
|
|
/// <summary>
|
|
/// 用户管理.
|
|
/// </summary>
|
|
private readonly IUserManager _userManager;
|
|
|
|
/// <summary>
|
|
/// 事件总线.
|
|
/// </summary>
|
|
private readonly IEventPublisher _eventPublisher;
|
|
|
|
/// <summary>
|
|
/// SqlSugarClient客户端.
|
|
/// </summary>
|
|
private SqlSugarScope _sqlSugarClient;
|
|
|
|
/// <summary>
|
|
/// 初始化一个<see cref="OAuthService"/>类型的新实例.
|
|
/// </summary>
|
|
public OAuthService(
|
|
IGeneralCaptcha captchaHandler,
|
|
ISqlSugarRepository<UserEntity> userRepository,
|
|
IModuleService moduleService,
|
|
IModuleButtonService moduleButtonService,
|
|
IModuleColumnService columnService,
|
|
IModuleDataAuthorizeSchemeService moduleDataAuthorizeSchemeService,
|
|
IModuleFormService formService,
|
|
ISysConfigService sysConfigService,
|
|
ISocialsUserService socialsUserService,
|
|
IOptions<ConnectionStringsOptions> connectionOptions,
|
|
IOptions<TenantOptions> tenantOptions,
|
|
ISqlSugarClient sqlSugarClient,
|
|
IHttpContextAccessor httpContextAccessor,
|
|
ICacheManager cacheManager,
|
|
IUserManager userManager,
|
|
IEventPublisher eventPublisher)
|
|
{
|
|
_captchaHandler = captchaHandler;
|
|
_userRepository = userRepository;
|
|
_moduleService = moduleService;
|
|
_moduleButtonService = moduleButtonService;
|
|
_columnService = columnService;
|
|
_moduleDataAuthorizeSchemeService = moduleDataAuthorizeSchemeService;
|
|
_formService = formService;
|
|
_sysConfigService = sysConfigService;
|
|
_socialsUserService = socialsUserService;
|
|
_connectionStrings = connectionOptions.Value;
|
|
_tenant = tenantOptions.Value;
|
|
_sqlSugarClient = (SqlSugarScope)sqlSugarClient;
|
|
_httpContextAccessor = httpContextAccessor;
|
|
_cacheManager = cacheManager;
|
|
_userManager = userManager;
|
|
_eventPublisher = eventPublisher;
|
|
}
|
|
|
|
#region Get
|
|
|
|
/// <summary>
|
|
/// 获取图形验证码.
|
|
/// </summary>
|
|
/// <param name="codeLength">验证码长度.</param>
|
|
/// <param name="timestamp">时间戳.</param>
|
|
/// <returns></returns>
|
|
[HttpGet("ImageCode/{codeLength}/{timestamp}")]
|
|
[AllowAnonymous]
|
|
[IgnoreLog]
|
|
[NonUnify]
|
|
public async Task<IActionResult> GetCode(int codeLength, string timestamp)
|
|
{
|
|
return new FileContentResult(await _captchaHandler.CreateCaptchaImage(timestamp, 120, 40, codeLength > 0 ? codeLength : 4), "image/jpeg");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 首次登录 根据账号获取数据库配置.
|
|
/// </summary>
|
|
/// <param name="account">账号.</param>
|
|
[HttpGet("getConfig/{account}")]
|
|
[AllowAnonymous]
|
|
[IgnoreLog]
|
|
public async Task<dynamic> GetConfigCode(string account)
|
|
{
|
|
ConnectionConfigOptions options = new ConnectionConfigOptions();
|
|
if (_tenant.MultiTenancy)
|
|
{
|
|
string tenantDbName = _connectionStrings.DBName;
|
|
string tenantId = _connectionStrings.ConfigId;
|
|
string tenantAccout = string.Empty;
|
|
|
|
// 分割账号
|
|
var tenantAccount = account.Split('@');
|
|
tenantId = tenantAccount.FirstOrDefault();
|
|
|
|
if (tenantAccount.Length == 1) account = "admin";
|
|
else account = tenantAccount[1];
|
|
|
|
tenantAccout = account;
|
|
|
|
var interFace = string.Format("{0}{1}", _tenant.MultiTenancyDBInterFace, tenantId);
|
|
var response = await interFace.GetAsStringAsync();
|
|
var result = response.ToObject<RESTfulResult<TenantInterFaceOutput>>();
|
|
if (result.code != 200)
|
|
{
|
|
throw Oops.Oh(result.msg);
|
|
}
|
|
else if (result.data.dotnet == null && result.data.linkList == null)
|
|
{
|
|
throw Oops.Oh(ErrorCode.D1025);
|
|
}
|
|
else
|
|
{
|
|
if (result.data.linkList == null || result.data.linkList?.Count == 0)
|
|
{
|
|
options = JNPFTenantExtensions.GetLinkToOrdinary(tenantId, result.data.dotnet);
|
|
}
|
|
else if (result.data.dotnet == null)
|
|
{
|
|
options = JNPFTenantExtensions.GetLinkToCustom(tenantId, result.data.linkList);
|
|
}
|
|
}
|
|
|
|
_sqlSugarClient.AddConnection(JNPFTenantExtensions.GetConfig(options));
|
|
_sqlSugarClient.ChangeDatabase(tenantId);
|
|
}
|
|
|
|
// 验证连接是否成功
|
|
if (!_sqlSugarClient.Ado.IsValidConnection()) throw Oops.Oh(ErrorCode.D1032);
|
|
|
|
// 读取配置文件
|
|
var array = new Dictionary<string, object>();
|
|
var sysConfigData = await _sqlSugarClient.Queryable<SysConfigEntity>()
|
|
.Where(x => x.Category.Equals("SysConfig") && (SqlFunc.ToLower(x.Key).Equals("enableverificationcode") || SqlFunc.ToLower(x.Key).Equals("verificationcodenumber"))).ToListAsync();
|
|
foreach (var item in sysConfigData)
|
|
{
|
|
if (!array.ContainsKey(item.Key)) array.Add(item.Key, item.Value);
|
|
}
|
|
|
|
var sysConfig = array.ToObject<SysConfigModel>();
|
|
|
|
// 返回给前端 是否开启验证码 和 验证码长度
|
|
return new { enableVerificationCode = sysConfig.enableVerificationCode, verificationCodeNumber = sysConfig.verificationCodeNumber > 0 ? sysConfig.verificationCodeNumber : 4 };
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取当前登录用户信息.
|
|
/// </summary>
|
|
/// <param name="type">Web和App</param>
|
|
/// <returns></returns>
|
|
[HttpGet("CurrentUser")]
|
|
public async Task<dynamic> GetCurrentUser(string type)
|
|
{
|
|
if (type.IsNullOrEmpty()) type = "Web"; // 默认为Web端菜单目录
|
|
|
|
var userId = _userManager.UserId;
|
|
|
|
var loginOutput = new CurrentUserOutput();
|
|
loginOutput.userInfo = await _userManager.GetUserInfo();
|
|
|
|
// 菜单
|
|
loginOutput.menuList = await _moduleService.GetUserTreeModuleList(type);
|
|
|
|
// 子系统信息
|
|
loginOutput.userInfo.systemIds = await _userRepository.AsSugarClient().Queryable<SystemEntity>().Where(x => x.DeleteMark == null && x.EnabledMark.Equals(1))
|
|
.Select(x => new UserSystemModel()
|
|
{
|
|
id = x.Id,
|
|
enCode = x.EnCode,
|
|
name = x.FullName,
|
|
icon = x.Icon,
|
|
sortCode = x.SortCode,
|
|
currentSystem = SqlFunc.Equals(loginOutput.userInfo.systemId, x.Id)
|
|
}).OrderBy(x => x.sortCode).ToListAsync();
|
|
|
|
if (!_userManager.IsAdministrator)
|
|
{
|
|
var sId = await _userRepository.AsSugarClient().Queryable<AuthorizeEntity>()
|
|
.Where(x => x.ItemType.Equals("system") && loginOutput.userInfo.roleIds.Contains(x.ObjectId) && x.ObjectType.Equals("Role"))
|
|
.Select(x => x.ItemId).ToListAsync();
|
|
loginOutput.userInfo.systemIds = loginOutput.userInfo.systemIds.Where(x => sId.Contains(x.id)).ToList();
|
|
|
|
if ((loginOutput.userInfo.systemIds.Any() && !loginOutput.userInfo.systemIds.Any(x => x.id.Equals(loginOutput.userInfo.systemId))) || loginOutput.userInfo.systemId.IsNullOrEmpty())
|
|
{
|
|
var defaultItem = loginOutput.userInfo.systemIds.Find(x => x.enCode.Equals("mainSystem"));
|
|
if (defaultItem == null) defaultItem = loginOutput.userInfo.systemIds.FirstOrDefault();
|
|
loginOutput.userInfo.systemId = defaultItem.id;
|
|
defaultItem.currentSystem = true;
|
|
await _userRepository.AsUpdateable().SetColumns(x => x.SystemId == loginOutput.userInfo.systemId).Where(x => x.Id.Equals(userId)).ExecuteCommandAsync();
|
|
loginOutput.menuList = await _moduleService.GetUserTreeModuleList(type);
|
|
}
|
|
|
|
if (!loginOutput.userInfo.systemIds.Any()) loginOutput.menuList.Clear();
|
|
}
|
|
|
|
var currentUserModel = new CurrentUserModelOutput();
|
|
currentUserModel.moduleList = await _moduleService.GetUserModueList(type);
|
|
currentUserModel.buttonList = await _moduleButtonService.GetUserModuleButtonList();
|
|
currentUserModel.columnList = await _columnService.GetUserModuleColumnList();
|
|
currentUserModel.resourceList = await _moduleDataAuthorizeSchemeService.GetResourceList();
|
|
currentUserModel.formList = await _formService.GetUserModuleFormList();
|
|
|
|
// 权限信息
|
|
var permissionList = new List<PermissionModel>();
|
|
currentUserModel.moduleList.ForEach(menu =>
|
|
{
|
|
var permissionModel = new PermissionModel();
|
|
permissionModel.modelId = menu.id;
|
|
permissionModel.moduleName = menu.fullName;
|
|
permissionModel.button = currentUserModel.buttonList.FindAll(t => t.moduleId.Equals(menu.id)).Adapt<List<FunctionalButtonAuthorizeModel>>();
|
|
permissionModel.column = currentUserModel.columnList.FindAll(t => t.moduleId.Equals(menu.id)).Adapt<List<FunctionalColumnAuthorizeModel>>();
|
|
permissionModel.form = currentUserModel.formList.FindAll(t => t.moduleId.Equals(menu.id)).Adapt<List<FunctionalFormAuthorizeModel>>();
|
|
permissionModel.resource = currentUserModel.resourceList.FindAll(t => t.moduleId.Equals(menu.id)).Adapt<List<FunctionalResourceAuthorizeModel>>();
|
|
permissionList.Add(permissionModel);
|
|
});
|
|
|
|
loginOutput.permissionList = permissionList;
|
|
|
|
// 系统+菜单树
|
|
loginOutput.routerList = new List<UserAllMenu>();
|
|
foreach (var item in loginOutput.userInfo.systemIds)
|
|
{
|
|
var sysMenuList = GetUserAllMenu(await _moduleService.GetUserTreeModuleListBySystemId(type, item.id));
|
|
sysMenuList.Where(x => x.systemId != null && x.systemId.Equals(item.id) && x.parentId.Equals("-1")).ToList().ForEach(it => it.parentId = item.id);
|
|
var child = sysMenuList.Where(x => x.systemId != null && x.systemId.Equals(item.id)).ToList();
|
|
loginOutput.routerList.Add(new UserAllMenu()
|
|
{
|
|
id = item.id,
|
|
fullName = item.name,
|
|
icon = item.icon,
|
|
enCode = item.enCode,
|
|
parentId = "-1",
|
|
children = child,
|
|
hasChildren = child.Any()
|
|
});
|
|
}
|
|
|
|
loginOutput.routerList = loginOutput.routerList.Where(x => x.parentId.Equals("-1")).ToList();
|
|
|
|
// 系统配置信息
|
|
var sysInfo = await _sysConfigService.GetInfo();
|
|
loginOutput.sysConfigInfo = sysInfo.Adapt<SysConfigInfo>();
|
|
|
|
return loginOutput;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 退出.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
[HttpGet("Logout")]
|
|
public async Task Logout()
|
|
{
|
|
var httpContext = _httpContextAccessor.HttpContext;
|
|
httpContext.SignoutToSwagger();
|
|
|
|
// 清除IM中的webSocket
|
|
var list = await GetOnlineUserList();
|
|
if (list != null)
|
|
{
|
|
var onlineUser = list.Find(it => it.tenantId == _userManager.TenantId && it.userId == _userManager.UserId);
|
|
if (onlineUser != null)
|
|
{
|
|
list.RemoveAll((x) => x.connectionId == onlineUser.connectionId);
|
|
await SetOnlineUserList(list);
|
|
}
|
|
}
|
|
|
|
await DelUserInfo();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region POST
|
|
|
|
/// <summary>
|
|
/// 用户登录.
|
|
/// </summary>
|
|
/// <param name="input">登录输入参数.</param>
|
|
/// <returns></returns>
|
|
[HttpPost("Login")]
|
|
[Consumes("application/x-www-form-urlencoded")]
|
|
[AllowAnonymous]
|
|
[IgnoreLog]
|
|
public async Task<dynamic> Login([FromForm] LoginInput input)
|
|
{
|
|
ConnectionConfigOptions options = JNPFTenantExtensions.GetLinkToOrdinary(_connectionStrings.ConfigId, _connectionStrings.DBName);
|
|
UserAgent userAgent = new UserAgent(App.HttpContext);
|
|
string tenantAccout = string.Empty;
|
|
string tenantId = string.Empty;
|
|
if (_tenant.MultiTenancy)
|
|
{
|
|
// 分割账号
|
|
var tenantAccount = input.account.Split('@');
|
|
tenantId = tenantAccount.FirstOrDefault();
|
|
if (tenantAccount.Length == 1)
|
|
input.account = "admin";
|
|
else
|
|
input.account = tenantAccount[1];
|
|
tenantAccout = input.account;
|
|
|
|
if (input.socialsOptions == null)
|
|
{
|
|
var interFace = string.Format("{0}{1}", _tenant.MultiTenancyDBInterFace, tenantId);
|
|
var response = await interFace.GetAsStringAsync();
|
|
var result = response.ToObject<RESTfulResult<TenantInterFaceOutput>>();
|
|
if (result.code != 200)
|
|
{
|
|
throw Oops.Oh(result.msg);
|
|
}
|
|
else if (result.data.dotnet == null && result.data.linkList == null)
|
|
{
|
|
throw Oops.Oh(ErrorCode.D1025);
|
|
}
|
|
else
|
|
{
|
|
if (result.data.linkList == null || result.data.linkList?.Count == 0)
|
|
{
|
|
options = JNPFTenantExtensions.GetLinkToOrdinary(tenantId, result.data.dotnet);
|
|
}
|
|
else if (result.data.dotnet == null)
|
|
{
|
|
options = JNPFTenantExtensions.GetLinkToCustom(tenantId, result.data.linkList);
|
|
}
|
|
}
|
|
|
|
_sqlSugarClient.AddConnection(JNPFTenantExtensions.GetConfig(options));
|
|
_sqlSugarClient.ChangeDatabase(tenantId);
|
|
}
|
|
else
|
|
{
|
|
options = input.socialsOptions;
|
|
}
|
|
}
|
|
|
|
// 验证连接是否成功
|
|
if (!_sqlSugarClient.Ado.IsValidConnection()) throw Oops.Oh(ErrorCode.D1032);
|
|
|
|
// 读取配置文件
|
|
var array = new Dictionary<string, string>();
|
|
var sysConfigData = await _sqlSugarClient.Queryable<SysConfigEntity>().Where(x => x.Category.Equals("SysConfig")).ToListAsync();
|
|
foreach (var item in sysConfigData)
|
|
{
|
|
if (!array.ContainsKey(item.Key)) array.Add(item.Key, item.Value);
|
|
}
|
|
|
|
var sysConfig = array.ToObject<SysConfigByOAuthModel>();
|
|
|
|
// 开启验证码验证
|
|
if (sysConfig.enableVerificationCode)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(input.timestamp) || string.IsNullOrWhiteSpace(input.code))
|
|
throw Oops.Oh(ErrorCode.D1029);
|
|
string imageCode = await GetCode(input.timestamp);
|
|
if (imageCode.IsNullOrEmpty())
|
|
throw Oops.Oh(ErrorCode.D1030);
|
|
if (!input.code.ToLower().Equals(imageCode.ToLower()))
|
|
throw Oops.Oh(ErrorCode.D1029);
|
|
}
|
|
|
|
// 根据用户账号获取用户秘钥
|
|
var user = await _sqlSugarClient.Queryable<UserEntity>().FirstAsync(it => it.Account.Equals(input.account) && it.DeleteMark == null);
|
|
_ = user ?? throw Oops.Oh(ErrorCode.D5002);
|
|
|
|
// 验证账号是否未被激活
|
|
if (user.EnabledMark == null) throw Oops.Oh(ErrorCode.D1018);
|
|
|
|
// 验证账号是否被禁用
|
|
if (user.EnabledMark == 0) throw Oops.Oh(ErrorCode.D1019);
|
|
|
|
// 验证账号是否被删除
|
|
if (user.DeleteMark == 1) throw Oops.Oh(ErrorCode.D1017);
|
|
|
|
// 是否延迟登录
|
|
if (sysConfig.lockType.Equals(ErrorStrategy.Delay) && user.UnLockTime.IsNullOrEmpty())
|
|
{
|
|
if (user.UnLockTime > DateTime.Now)
|
|
{
|
|
int unlockTime = ((user.UnLockTime - DateTime.Now)?.TotalMinutes).ParseToInt();
|
|
if (unlockTime < 1) unlockTime = 1;
|
|
throw Oops.Oh(ErrorCode.D1027, unlockTime);
|
|
}
|
|
else if (user.UnLockTime <= DateTime.Now)
|
|
{
|
|
user.EnabledMark = 1;
|
|
user.LogErrorCount = 0;
|
|
await _sqlSugarClient.Updateable(user).UpdateColumns(it => new { it.LogErrorCount, it.EnabledMark }).ExecuteCommandAsync();
|
|
}
|
|
}
|
|
|
|
// 是否 延迟登录
|
|
if (sysConfig.lockType.Equals(ErrorStrategy.Delay) && user.UnLockTime.IsNotEmptyOrNull() && user.UnLockTime > DateTime.Now)
|
|
{
|
|
int? t3 = (user.UnLockTime - DateTime.Now)?.TotalMinutes.ParseToInt();
|
|
if (t3 < 1) t3 = 1;
|
|
throw Oops.Oh(ErrorCode.D1027, t3?.ToString());
|
|
}
|
|
|
|
if (sysConfig.lockType.Equals(ErrorStrategy.Delay) && user.UnLockTime.IsNotEmptyOrNull() && user.UnLockTime <= DateTime.Now)
|
|
{
|
|
user.EnabledMark = 1;
|
|
user.LogErrorCount = 0;
|
|
await _sqlSugarClient.Updateable(user).UpdateColumns(it => new { it.LogErrorCount, it.EnabledMark }).ExecuteCommandAsync();
|
|
}
|
|
|
|
// 是否锁定
|
|
if (user.EnabledMark == 2) throw Oops.Oh(ErrorCode.D1031);
|
|
|
|
// 获取加密后的密码
|
|
var encryptPasswod = MD5Encryption.Encrypt(input.password + user.Secretkey);
|
|
if (input.isSocialsLoginCallBack) encryptPasswod = input.password;
|
|
|
|
// 账户密码是否匹配
|
|
var userAnyPwd = await _sqlSugarClient.Queryable<UserEntity>().FirstAsync(u => u.Account == input.account && u.Password == encryptPasswod && u.DeleteMark == null);
|
|
if (userAnyPwd.IsNullOrEmpty())
|
|
{
|
|
// 如果是密码错误 记录账号的密码错误次数
|
|
await UpdateErrorLog(user, sysConfig);
|
|
}
|
|
else
|
|
{
|
|
// 清空记录错误次数
|
|
userAnyPwd.LogErrorCount = 0;
|
|
|
|
// 解除锁定
|
|
userAnyPwd.EnabledMark = 1;
|
|
await _sqlSugarClient.Updateable(userAnyPwd).UpdateColumns(it => new { it.LogErrorCount, it.EnabledMark }).ExecuteCommandAsync();
|
|
}
|
|
|
|
_ = userAnyPwd ?? throw Oops.Oh(ErrorCode.D1000);
|
|
|
|
// app权限验证
|
|
if (userAgent.IsMobileDevice && user.IsAdministrator == 0 && !ExistRoleByApp(user.RoleId))
|
|
throw Oops.Oh(ErrorCode.D1022);
|
|
|
|
// 登录成功时 判断单点登录信息
|
|
int whitelistSwitch = Convert.ToInt32(sysConfig.whitelistSwitch);
|
|
string whiteListIp = sysConfig.whiteListIp;
|
|
if (whitelistSwitch.Equals(1) && user.IsAdministrator.Equals(0))
|
|
{
|
|
if (!whiteListIp.Split(",").Contains(NetHelper.Ip))
|
|
throw Oops.Oh(ErrorCode.D9002);
|
|
}
|
|
|
|
// token过期时间
|
|
long tokenTimeout = sysConfig.tokenTimeout;
|
|
|
|
// 生成Token令牌
|
|
string accessToken = JWTEncryption.Encrypt(
|
|
new Dictionary<string, object>
|
|
{
|
|
{ ClaimConst.CLAINMUSERID, userAnyPwd.Id },
|
|
{ ClaimConst.CLAINMACCOUNT, userAnyPwd.Account },
|
|
{ ClaimConst.CLAINMREALNAME, userAnyPwd.RealName },
|
|
{ ClaimConst.CLAINMADMINISTRATOR, userAnyPwd.IsAdministrator },
|
|
{ ClaimConst.TENANTID, options.ConfigId },
|
|
{ ClaimConst.CONNECTIONCONFIG, options},
|
|
{ ClaimConst.SINGLELOGIN, (int)sysConfig.singleLogin }
|
|
}, tokenTimeout);
|
|
|
|
// 设置Swagger自动登录
|
|
_httpContextAccessor.HttpContext.SigninToSwagger(accessToken);
|
|
|
|
// 设置刷新Token令牌
|
|
_httpContextAccessor.HttpContext.Response.Headers["x-access-token"] = JWTEncryption.GenerateRefreshToken(accessToken, 30); // 生成刷新Token令牌
|
|
|
|
var ip = NetHelper.Ip;
|
|
|
|
// 修改用户登录信息
|
|
await _eventPublisher.PublishAsync(new UserEventSource("User:UpdateUserLogin", options, new UserEntity
|
|
{
|
|
Id = user.Id,
|
|
FirstLogIP = user.FirstLogIP ?? ip,
|
|
FirstLogTime = user.FirstLogTime ?? DateTime.Now,
|
|
PrevLogTime = user.LastLogTime,
|
|
PrevLogIP = user.LastLogIP,
|
|
LastLogTime = DateTime.Now,
|
|
LastLogIP = ip,
|
|
LogSuccessCount = user.LogSuccessCount + 1
|
|
}));
|
|
|
|
// 增加登录日志
|
|
await _eventPublisher.PublishAsync(new LogEventSource("Log:CreateVisLog", options, new SysLogEntity
|
|
{
|
|
Id = SnowflakeIdHelper.NextId(),
|
|
UserId = user.Id,
|
|
UserName = user.RealName,
|
|
Category = 1,
|
|
IPAddress = ip,
|
|
Abstracts = "登录成功",
|
|
PlatForm = string.Format("{0}-{1}", userAgent.OS.ToString(), userAgent.RawValue),
|
|
CreatorTime = DateTime.Now
|
|
}));
|
|
|
|
var ticket = await _cacheManager.GetAsync<SocialsLoginTicketModel>(input.jnpf_ticket);
|
|
if (ticket.IsNotEmptyOrNull())
|
|
{
|
|
var socialsEntity = ticket.value.ToObject<SocialsUsersEntity>();
|
|
var sInfo = await _userRepository.AsSugarClient().Queryable<SocialsUsersEntity>().Where(x => (x.SocialId.Equals(socialsEntity.SocialId) || x.UserId.Equals(user.Id)) && x.SocialType.Equals(socialsEntity.SocialType) && x.DeleteMark == null).FirstAsync();
|
|
if (sInfo == null)
|
|
{
|
|
var socialsUserEntity = new SocialsUsersEntity();
|
|
socialsUserEntity.UserId = user.Id;
|
|
socialsUserEntity.SocialType = socialsEntity.SocialType.ToLower();
|
|
socialsUserEntity.SocialName = socialsEntity.SocialName;
|
|
socialsUserEntity.SocialId = socialsEntity.SocialId;
|
|
await _userRepository.AsSugarClient().Insertable(socialsUserEntity).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync();
|
|
|
|
// 租户开启时-添加租户库绑定数据
|
|
if (_tenant.MultiTenancy)
|
|
{
|
|
var info = await _userRepository.AsSugarClient().Queryable<UserEntity>().FirstAsync(x => x.Id.Equals(user.Id));
|
|
var param = socialsUserEntity.ToObject<Dictionary<string, string>>();
|
|
if (param.ContainsKey("SocialType")) param["SocialType"] = param["SocialType"].ToLower();
|
|
param.Add("tenantId", tenantId);
|
|
param.Add("account", info.Account);
|
|
param.Add("accountName", info.RealName + "/" + info.Account);
|
|
|
|
var postUrl = _tenant.MultiTenancyDBInterFace + "socials";
|
|
var result = (await postUrl.SetBody(param).PostAsStringAsync()).ToObject<Dictionary<string, string>>();
|
|
|
|
if (result == null || "500".Equals(result["code"]) || "400".Equals(result["code"]))
|
|
{
|
|
return new { code = 201, message = "用户租户绑定错误!" }.ToJsonString();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return new
|
|
{
|
|
theme = user.Theme == null ? "classic" : user.Theme,
|
|
token = string.Format("Bearer {0}", accessToken)
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// 锁屏解锁登录.
|
|
/// </summary>
|
|
/// <param name="input">登录输入参数.</param>
|
|
/// <returns></returns>
|
|
[HttpPost("LockScreen")]
|
|
public async Task LockScreen([FromBody] LockScreenInput input)
|
|
{
|
|
// 根据用户账号获取用户秘钥
|
|
var secretkey = (await _userRepository.GetFirstAsync(u => u.Account == input.account && u.DeleteMark == null)).Secretkey;
|
|
|
|
// 获取加密后的密码
|
|
var encryptPasswod = MD5Encryption.Encrypt(input.password + secretkey);
|
|
|
|
var user = await _userRepository.GetFirstAsync(u => u.Account == input.account && u.Password == encryptPasswod && u.DeleteMark == null);
|
|
_ = user ?? throw Oops.Oh(ErrorCode.D1000);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 注销用户.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
[HttpPost("logoutCurrentUser")]
|
|
[NonUnify]
|
|
public async Task<dynamic> LogoutCurrentUser()
|
|
{
|
|
var userInfo = _userManager.User;
|
|
if (userInfo.IsAdministrator.Equals(1)) throw Oops.Oh(ErrorCode.D1034);
|
|
userInfo.DeleteMark = 1;
|
|
userInfo.DeleteTime = DateTime.Now;
|
|
userInfo.DeleteUserId = userInfo.Id;
|
|
await _userRepository.AsUpdateable(userInfo).ExecuteCommandAsync();
|
|
return new { code = 200, msg = "注销成功" };
|
|
}
|
|
#endregion
|
|
|
|
#region PrivateMethod
|
|
|
|
/// <summary>
|
|
/// 获取验证码.
|
|
/// </summary>
|
|
/// <param name="timestamp">时间戳.</param>
|
|
/// <returns></returns>
|
|
private async Task<string> GetCode(string timestamp)
|
|
{
|
|
string cacheKey = string.Format("{0}{1}", CommonConst.CACHEKEYCODE, timestamp);
|
|
return await _cacheManager.GetAsync<string>(cacheKey);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 判断app用户角色是否存在且有效.
|
|
/// </summary>
|
|
/// <param name="roleIds"></param>
|
|
/// <returns></returns>
|
|
private bool ExistRoleByApp(string roleIds)
|
|
{
|
|
if (roleIds.IsEmpty())
|
|
return false;
|
|
var roleIdList1 = roleIds.Split(",").ToList();
|
|
var roleIdList2 = _sqlSugarClient.Queryable<RoleEntity>().Where(x => x.DeleteMark == null && x.EnabledMark == 1).Select(x => x.Id).ToList();
|
|
return roleIdList1.Intersect(roleIdList2).ToList().Count > 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 记录密码错误次数.
|
|
/// </summary>
|
|
/// <param name="entity">用户实体.</param>
|
|
/// <param name="sysConfigOutput">系统配置输出.</param>
|
|
/// <returns></returns>
|
|
private async Task UpdateErrorLog(UserEntity entity, SysConfigByOAuthModel sysConfigOutput)
|
|
{
|
|
if (entity != null)
|
|
{
|
|
if (entity.EnabledMark.Equals(1) && !entity.Account.ToLower().Equals("admin") && sysConfigOutput.lockType > 0 && sysConfigOutput.passwordErrorsNumber > 2)
|
|
{
|
|
|
|
switch (sysConfigOutput.lockType)
|
|
{
|
|
case ErrorStrategy.Lock:
|
|
entity.EnabledMark = entity.LogErrorCount >= sysConfigOutput.passwordErrorsNumber - 1 ? 2 : 1;
|
|
break;
|
|
case ErrorStrategy.Delay:
|
|
entity.UnLockTime = entity.LogErrorCount >= sysConfigOutput.passwordErrorsNumber - 1 ? DateTime.Now.AddMinutes(sysConfigOutput.lockTime) : null;
|
|
entity.EnabledMark = entity.LogErrorCount >= sysConfigOutput.passwordErrorsNumber - 1 ? 2 : 1;
|
|
break;
|
|
}
|
|
|
|
entity.LogErrorCount++;
|
|
|
|
await _sqlSugarClient.Updateable(entity).UpdateColumns(it => new { it.EnabledMark, it.UnLockTime, it.LogErrorCount }).ExecuteCommandAsync();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取在线用户列表.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private async Task<List<UserOnlineModel>> GetOnlineUserList()
|
|
{
|
|
string cacheKey = string.Format("{0}{1}", CommonConst.CACHEKEYONLINEUSER, _userManager.ConnectionConfig.ConfigId);
|
|
return await _cacheManager.GetAsync<List<UserOnlineModel>>(cacheKey);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存在线用户列表.
|
|
/// </summary>
|
|
/// <param name="onlineList">在线用户列表.</param>
|
|
/// <returns></returns>
|
|
private async Task<bool> SetOnlineUserList(List<UserOnlineModel> onlineList)
|
|
{
|
|
string cacheKey = string.Format("{0}{1}", CommonConst.CACHEKEYONLINEUSER, _userManager.ConnectionConfig.ConfigId);
|
|
return await _cacheManager.SetAsync(cacheKey, onlineList);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 删除用户登录信息缓存.
|
|
/// </summary>
|
|
private async Task<bool> DelUserInfo()
|
|
{
|
|
string cacheKey = string.Format("{0}{1}_{2}", CommonConst.CACHEKEYUSER, _userManager.ConnectionConfig.ConfigId, _userManager.UserId);
|
|
return await _cacheManager.DelAsync(cacheKey);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 组装用户所有菜单.
|
|
/// </summary>
|
|
/// <param name="menuList"></param>
|
|
/// <returns></returns>
|
|
private List<UserAllMenu> GetUserAllMenu(List<ModuleNodeOutput> menuList)
|
|
{
|
|
var result = new List<UserAllMenu>();
|
|
menuList.ForEach(item =>
|
|
{
|
|
var menu = item.Adapt<UserAllMenu>();
|
|
if (menu.children != null && menu.children.Any())
|
|
{
|
|
menu.hasChildren = true;
|
|
menu.children = GetUserAllMenu(menu.children.Adapt<List<ModuleNodeOutput>>());
|
|
}
|
|
|
|
result.Add(menu);
|
|
});
|
|
|
|
return result;
|
|
}
|
|
#endregion
|
|
|
|
#region 第三方登录回调
|
|
|
|
/// <summary>
|
|
/// 第三方登录回调.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
[HttpGet("Login/socials")]
|
|
[AllowAnonymous]
|
|
[IgnoreLog]
|
|
[NonUnify]
|
|
public async Task<dynamic> SocialsLoginCallBack([FromQuery] SocialsUserInputModel req)
|
|
{
|
|
ConnectionConfigOptions options = null;
|
|
|
|
if (req.tenantLogin && req.tenantId.IsNotEmptyOrNull() && req.userId.IsNotEmptyOrNull())
|
|
{
|
|
options = JNPFTenantExtensions.GetLinkToOrdinary(_connectionStrings.ConfigId, _connectionStrings.DBName);
|
|
var interFace = string.Format("{0}{1}", _tenant.MultiTenancyDBInterFace, req.tenantId);
|
|
var response = await interFace.GetAsStringAsync();
|
|
var resultObj = response.ToObject<RESTfulResult<TenantInterFaceOutput>>();
|
|
if (resultObj.code != 200)
|
|
{
|
|
throw Oops.Oh(resultObj.msg);
|
|
}
|
|
else if (resultObj.data.dotnet == null && resultObj.data.linkList == null)
|
|
{
|
|
throw Oops.Oh(ErrorCode.D1025);
|
|
}
|
|
else
|
|
{
|
|
if (resultObj.data.linkList == null || resultObj.data.linkList?.Count == 0)
|
|
{
|
|
options = JNPFTenantExtensions.GetLinkToOrdinary(req.tenantId, resultObj.data.dotnet);
|
|
}
|
|
else if (resultObj.data.dotnet == null)
|
|
{
|
|
options = JNPFTenantExtensions.GetLinkToCustom(req.tenantId, resultObj.data.linkList);
|
|
}
|
|
}
|
|
|
|
_sqlSugarClient.AddConnection(JNPFTenantExtensions.GetConfig(options));
|
|
_sqlSugarClient.ChangeDatabase(req.tenantId);
|
|
var userEntity = await _userRepository.AsQueryable().FirstAsync(x => x.Id.Equals(req.userId));
|
|
if (_tenant.MultiTenancy) userEntity.Account = req.tenantId + "@" + userEntity.Account;
|
|
var result = await Login(new LoginInput() { account = userEntity.Account, password = userEntity.Password, isSocialsLoginCallBack = true, socialsOptions = options });
|
|
return new { code = 200, data = result };
|
|
}
|
|
|
|
if (_tenant.MultiTenancy && req.tenantId.IsNullOrEmpty())
|
|
{
|
|
var result = new AuthResponse(5001, string.Empty);
|
|
var resStr = string.Empty;
|
|
|
|
// 微信小程序唤醒登录.
|
|
if (req.uuid.IsNotEmptyOrNull())
|
|
{
|
|
AuthUser user = new AuthUser();
|
|
user.uuid = req.uuid;
|
|
user.source = req.source;
|
|
user.username = req.socialName;
|
|
result = new AuthResponse(2000, null, user);
|
|
}
|
|
else
|
|
{
|
|
if (req.code.IsNullOrWhiteSpace()) req.code = req.authCode != null ? req.authCode : req.auth_code;
|
|
|
|
// 获取第三方请求
|
|
AuthCallbackNew callback = _socialsUserService.SetAuthCallback(req.code, req.state);
|
|
|
|
// 获取第三方请求
|
|
var authRequest = _socialsUserService.GetAuthRequest(req.source, null, false, null, null);
|
|
result = authRequest.login(callback);
|
|
}
|
|
|
|
if (result.ok())
|
|
{
|
|
var resData = result.data.ToObject<AuthUser>();
|
|
var uuid = _socialsUserService.GetSocialUuid(result);
|
|
|
|
options = JNPFTenantExtensions.GetLinkToOrdinary(_connectionStrings.ConfigId, _connectionStrings.DBName);
|
|
var interFace = string.Format("{0}socials/list?socialsId={1}", _tenant.MultiTenancyDBInterFace, uuid);
|
|
var response = await interFace.GetAsStringAsync();
|
|
var resultObj = response.ToObject<Dictionary<string, object>>();
|
|
if (resultObj["code"].ToString() != "200")
|
|
{
|
|
throw Oops.Oh(resultObj["msg"].ToString());
|
|
}
|
|
|
|
var ticket = _cacheManager.Get<SocialsLoginTicketModel>(req.jnpf_ticket);
|
|
if (ticket == null && req.code.IsNullOrWhiteSpace()) Oops.Oh(ErrorCode.D1035);
|
|
if (ticket.IsNotEmptyOrNull())
|
|
{
|
|
// 修改 缓存 状态
|
|
ticket.status = (int)SocialsLoginTicketStatus.Multitenancy;
|
|
if (resultObj["data"] != null && resultObj["data"].ToJsonString().Equals("[]"))
|
|
{
|
|
if (result.ok())
|
|
{
|
|
var socialsUserEntity = new SocialsUsersEntity();
|
|
socialsUserEntity.SocialType = resData.source;
|
|
socialsUserEntity.SocialName = resData.username;
|
|
socialsUserEntity.SocialId = uuid;
|
|
ticket.status = (int)SocialsLoginTicketStatus.UnBind;
|
|
ticket.value = socialsUserEntity.ToJsonString();
|
|
_cacheManager.Set(req.jnpf_ticket, ticket, TimeSpan.FromMinutes(5));
|
|
resStr = new { code = 400, msg = "等待登录自动绑定!", message = "等待登录自动绑定!" }.ToJsonString();
|
|
}
|
|
else
|
|
{
|
|
resStr = new { code = 400, msg = "第三方回调失败!", message = "第三方回调失败!" }.ToJsonString();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var tList = resultObj["data"].ToObject<List<Dictionary<string, object>>>();
|
|
if (tList.Count == 1)
|
|
{
|
|
var tInfo = tList.FirstOrDefault();
|
|
interFace = string.Format("{0}{1}", _tenant.MultiTenancyDBInterFace, tInfo["tenantId"]);
|
|
response = await interFace.GetAsStringAsync();
|
|
var resObj = response.ToObject<RESTfulResult<TenantInterFaceOutput>>();
|
|
if (resObj.code != 200)
|
|
{
|
|
throw Oops.Oh(resObj.msg);
|
|
}
|
|
else if (resObj.data.dotnet == null && resObj.data.linkList == null)
|
|
{
|
|
throw Oops.Oh(ErrorCode.D1025);
|
|
}
|
|
else
|
|
{
|
|
if (resObj.data.linkList == null || resObj.data.linkList?.Count == 0)
|
|
{
|
|
options = JNPFTenantExtensions.GetLinkToOrdinary(tInfo["tenantId"].ToString(), resObj.data.dotnet);
|
|
}
|
|
else if (resObj.data.dotnet == null)
|
|
{
|
|
options = JNPFTenantExtensions.GetLinkToCustom(tInfo["tenantId"].ToString(), resObj.data.linkList);
|
|
}
|
|
}
|
|
|
|
_sqlSugarClient.AddConnection(JNPFTenantExtensions.GetConfig(options));
|
|
_sqlSugarClient.ChangeDatabase(tInfo["tenantId"]);
|
|
var userEntity = await _userRepository.AsQueryable().FirstAsync(x => x.Id.Equals(tInfo["userId"].ToString()));
|
|
if (_tenant.MultiTenancy) userEntity.Account = tInfo["tenantId"].ToString() + "@" + userEntity.Account;
|
|
var loginRes = await Login(new LoginInput() { account = userEntity.Account, password = userEntity.Password, isSocialsLoginCallBack = true, socialsOptions = options });
|
|
|
|
// 修改 缓存 状态
|
|
ticket.status = (int)SocialsLoginTicketStatus.Success;
|
|
ticket.value = loginRes.token;
|
|
_cacheManager.Set(req.jnpf_ticket, ticket.ToJsonString(), TimeSpan.FromMinutes(5));
|
|
return new { code = 200, data = ticket };
|
|
}
|
|
ticket.value = resultObj["data"].ToJsonString();
|
|
_cacheManager.Set(req.jnpf_ticket, ticket.ToJsonString(), TimeSpan.FromMinutes(5));
|
|
resStr = new { code = 200, data = ticket.value }.ToJsonString();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
resStr = new { code = 400, msg = "第三方回调失败!", message = "第三方回调失败!" }.ToJsonString();
|
|
}
|
|
|
|
if (req.jnpf_ticket.IsNullOrEmpty())
|
|
{
|
|
App.HttpContext.Response.ContentType = "text/html;charset=utf-8";
|
|
await App.HttpContext.Response.WriteAsync(string.Format("<script>window.opener.postMessage('{0}', '*');window.open('','_self','');window.close();</script>", resStr));
|
|
}
|
|
|
|
return resStr.ToObject<Dictionary<string, object>>();
|
|
}
|
|
if (_tenant.MultiTenancy && req.tenantId.IsNotEmptyOrNull())
|
|
{
|
|
options = JNPFTenantExtensions.GetLinkToOrdinary(_connectionStrings.ConfigId, _connectionStrings.DBName);
|
|
var interFace = string.Format("{0}{1}", _tenant.MultiTenancyDBInterFace, req.tenantId);
|
|
var response = await interFace.GetAsStringAsync();
|
|
var resultObj = response.ToObject<RESTfulResult<TenantInterFaceOutput>>();
|
|
if (resultObj.code != 200)
|
|
{
|
|
throw Oops.Oh(resultObj.msg);
|
|
}
|
|
else if (resultObj.data.dotnet == null && resultObj.data.linkList == null)
|
|
{
|
|
throw Oops.Oh(ErrorCode.D1025);
|
|
}
|
|
else
|
|
{
|
|
if (resultObj.data.linkList == null || resultObj.data.linkList?.Count == 0)
|
|
{
|
|
options = JNPFTenantExtensions.GetLinkToOrdinary(req.tenantId, resultObj.data.dotnet);
|
|
}
|
|
else if (resultObj.data.dotnet == null)
|
|
{
|
|
options = JNPFTenantExtensions.GetLinkToCustom(req.tenantId, resultObj.data.linkList);
|
|
}
|
|
}
|
|
|
|
_sqlSugarClient.AddConnection(JNPFTenantExtensions.GetConfig(options));
|
|
_sqlSugarClient.ChangeDatabase(req.tenantId);
|
|
}
|
|
|
|
if (req.code.IsNullOrWhiteSpace()) req.code = req.authCode != null ? req.authCode : req.auth_code;
|
|
|
|
var res = await _socialsUserService.Binding(req);
|
|
|
|
if (req.jnpf_ticket.IsNotEmptyOrNull())
|
|
{
|
|
var ticket = _cacheManager.Get<SocialsLoginTicketModel>(req.jnpf_ticket);
|
|
if (ticket == null && req.code.IsNullOrWhiteSpace()) Oops.Oh(ErrorCode.D1035);
|
|
|
|
var data = res.ToObject<Dictionary<string, object>>();
|
|
if (data.ContainsKey("data"))
|
|
{
|
|
var socialsEntity = data["data"].ToObject<SocialsUsersEntity>();
|
|
|
|
// 接受CODE 进行登录
|
|
var sEntity = await _userRepository.AsSugarClient().Queryable<SocialsUsersEntity>().FirstAsync(x => x.SocialType.Equals(socialsEntity.SocialType) && x.SocialId.Equals(socialsEntity.SocialId) && x.DeleteMark == null);
|
|
if (sEntity != null)
|
|
{
|
|
var userEntity = await _userRepository.AsQueryable().FirstAsync(x => x.Id.Equals(sEntity.UserId));
|
|
if (_tenant.MultiTenancy) userEntity.Account = req.tenantId + "@" + userEntity.Account;
|
|
var loginRes = await Login(new LoginInput() { account = userEntity.Account, password = userEntity.Password, isSocialsLoginCallBack = true, socialsOptions = options });
|
|
|
|
// 修改 缓存 状态
|
|
ticket.status = (int)SocialsLoginTicketStatus.Success;
|
|
ticket.value = loginRes.token;
|
|
_cacheManager.Set(req.jnpf_ticket, ticket.ToJsonString(), TimeSpan.FromMinutes(5));
|
|
return new { code = 200, data = ticket };
|
|
}
|
|
else
|
|
{
|
|
var ticketValue = _cacheManager.Get(req.jnpf_ticket);
|
|
if (ticketValue.IsNotEmptyOrNull())
|
|
{
|
|
ticket.status = (int)SocialsLoginTicketStatus.UnBind;
|
|
ticket.value = socialsEntity.ToJsonString();
|
|
_cacheManager.Set(req.jnpf_ticket, ticket, TimeSpan.FromMinutes(5));
|
|
res = new { code = 400, msg = "等待登录自动绑定!", message = "等待登录自动绑定!" }.ToJsonString();
|
|
}
|
|
else
|
|
{
|
|
res = new { code = 400, msg = "第三方回调失败!", message = "第三方回调失败!" }.ToJsonString();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
res = new { code = 400, msg = "第三方回调失败!", message = "第三方回调失败!" }.ToJsonString();
|
|
}
|
|
}
|
|
|
|
if (req.jnpf_ticket.IsNullOrEmpty())
|
|
{
|
|
var result = res.ToObject<Dictionary<string, object>>();
|
|
if (result.ContainsKey("data")) result.Remove("data");
|
|
App.HttpContext.Response.StatusCode = 200;
|
|
App.HttpContext.Response.ContentType = "text/html;charset=utf-8";
|
|
await App.HttpContext.Response.WriteAsync(string.Format("<script>window.opener.postMessage('{0}', '*');window.open('','_self','');window.close();</script>", result.ToJsonString()));
|
|
}
|
|
|
|
return res.ToObject<Dictionary<string, object>>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 多租户第三方登录回调.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
[HttpPost("Login/socials")]
|
|
[Consumes("application/x-www-form-urlencoded")]
|
|
[AllowAnonymous]
|
|
[IgnoreLog]
|
|
public async Task<dynamic> SocialsLogin([FromForm] SocialsUserCallBackModel req)
|
|
{
|
|
if (req.tenantLogin)
|
|
{
|
|
var options = JNPFTenantExtensions.GetLinkToOrdinary(_connectionStrings.ConfigId, _connectionStrings.DBName);
|
|
var interFace = string.Format("{0}{1}", _tenant.MultiTenancyDBInterFace, req.tenantId);
|
|
var response = await interFace.GetAsStringAsync();
|
|
var resultObj = response.ToObject<RESTfulResult<TenantInterFaceOutput>>();
|
|
if (resultObj.code != 200)
|
|
{
|
|
throw Oops.Oh(resultObj.msg);
|
|
}
|
|
else if (resultObj.data.dotnet == null && resultObj.data.linkList == null)
|
|
{
|
|
throw Oops.Oh(ErrorCode.D1025);
|
|
}
|
|
else
|
|
{
|
|
if (resultObj.data.linkList == null || resultObj.data.linkList?.Count == 0)
|
|
{
|
|
options = JNPFTenantExtensions.GetLinkToOrdinary(req.tenantId, resultObj.data.dotnet);
|
|
}
|
|
else if (resultObj.data.dotnet == null)
|
|
{
|
|
options = JNPFTenantExtensions.GetLinkToCustom(req.tenantId, resultObj.data.linkList);
|
|
}
|
|
}
|
|
|
|
_sqlSugarClient.AddConnection(JNPFTenantExtensions.GetConfig(options));
|
|
_sqlSugarClient.ChangeDatabase(req.tenantId);
|
|
var userEntity = await _userRepository.AsQueryable().FirstAsync(x => x.Id.Equals(req.userId));
|
|
if (_tenant.MultiTenancy) userEntity.Account = req.tenantId + "@" + userEntity.Account;
|
|
return await Login(new LoginInput() { account = userEntity.Account, password = userEntity.Password, isSocialsLoginCallBack = true, socialsOptions = options });
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取登录配置, 是否需要跳转、第三方登录信息.
|
|
/// </summary>
|
|
[HttpGet("GetLoginConfig")]
|
|
[AllowAnonymous]
|
|
[IgnoreLog]
|
|
public dynamic GetSocialsLoginConfig()
|
|
{
|
|
var loginConfigModel = new SocialsLoginConfigModel();
|
|
|
|
// 追加第三方登录配置
|
|
var loginList = _socialsUserService.GetLoginList(CommonConst.PARAMS_JNPF_TICKET.ToUpper());
|
|
if (loginList == null) return loginConfigModel;
|
|
if (loginList.Any())
|
|
{
|
|
loginConfigModel.socialsList = loginList.ToObject<List<object>>();
|
|
loginConfigModel.redirect = false;
|
|
loginConfigModel.ticketParams = CommonConst.PARAMS_JNPF_TICKET;
|
|
}
|
|
|
|
return loginConfigModel;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取登录票据.
|
|
/// </summary>
|
|
/// <returns>return {msg:有效期, data:票据}.</returns>
|
|
[HttpGet("getTicket")]
|
|
[AllowAnonymous]
|
|
[IgnoreLog]
|
|
public dynamic GetTicket()
|
|
{
|
|
SocialsLoginTicketModel ticketModel = new SocialsLoginTicketModel();
|
|
var curDate = DateTime.Now.AddMinutes(5); // 默认过期5分钟.
|
|
ticketModel.ticketTimeout = curDate.ParseToUnixTime();
|
|
var key = "SocialsLogin_" + Yitter.IdGenerator.YitIdHelper.NextId().ToString();
|
|
_cacheManager.Set(key, ticketModel.ToJsonString(), TimeSpan.FromMinutes(5));
|
|
return key;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 检测票据登录状态.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
[HttpGet("getTicketStatus/{ticket}")]
|
|
[AllowAnonymous]
|
|
[IgnoreLog]
|
|
public dynamic GetTicketStatus(string ticket)
|
|
{
|
|
var ticketModel = _cacheManager.Get<SocialsLoginTicketModel>(ticket);
|
|
if (ticketModel == null)
|
|
{
|
|
ticketModel = new SocialsLoginTicketModel() { status = (int)SocialsLoginTicketStatus.Invalid };
|
|
}
|
|
|
|
return ticketModel;
|
|
}
|
|
|
|
#endregion
|
|
} |