using JNPF.Common.Captcha.General;
using JNPF.Common.Const;
using JNPF.Common.Core.Handlers;
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;
using JNPF.Common.Models.User;
using JNPF.Common.Net;
using JNPF.Common.Options;
using JNPF.Common.Security;
using JNPF.DataEncryption;
using JNPF.DependencyInjection;
using JNPF.DynamicApiController;
using JNPF.EventBus;
using JNPF.EventHandler;
using JNPF.Extras.CollectiveOAuth.Models;
using JNPF.Extras.DatabaseAccessor.SqlSugar.Models;
using JNPF.FriendlyException;
using JNPF.Logging.Attributes;
using JNPF.Message.Interfaces.Message;
using JNPF.OAuth.Dto;
using JNPF.OAuth.Model;
using JNPF.RemoteRequest.Extensions;
using JNPF.Systems.Entitys.Dto.Module;
using JNPF.Systems.Entitys.Enum;
using JNPF.Systems.Entitys.Model.Permission.SocialsUser;
using JNPF.Systems.Entitys.Model.SysConfig;
using JNPF.Systems.Entitys.Permission;
using JNPF.Systems.Entitys.System;
using JNPF.Systems.Interfaces.Permission;
using JNPF.Systems.Interfaces.System;
using JNPF.UnifyResult;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using SqlSugar;
namespace JNPF.OAuth;
///
/// 业务实现:身份认证模块 .
///
[ApiDescriptionSettings(Tag = "OAuth", Name = "OAuth", Order = 160)]
[Route("api/[controller]")]
public class OAuthService : IDynamicApiController, ITransient
{
///
/// 配置文档.
///
private readonly OauthOptions _oauthOptions = App.GetConfig("OAuth", true);
///
/// 用户仓储.
///
private readonly ISqlSugarRepository _userRepository;
///
/// 功能模块.
///
private readonly IModuleService _moduleService;
///
/// 功能按钮.
///
private readonly IModuleButtonService _moduleButtonService;
///
/// 功能列.
///
private readonly IModuleColumnService _columnService;
///
/// 功能数据权限计划.
///
private readonly IModuleDataAuthorizeSchemeService _moduleDataAuthorizeSchemeService;
///
/// 功能表单.
///
private readonly IModuleFormService _formService;
///
/// 系统配置.
///
private readonly ISysConfigService _sysConfigService;
///
/// 验证码处理程序.
///
private readonly IGeneralCaptcha _captchaHandler;
///
/// 第三方登录.
///
private readonly ISocialsUserService _socialsUserService;
///
/// 数据库配置选项.
///
private readonly ConnectionStringsOptions _connectionStrings;
///
/// 多租户配置选项.
///
private readonly TenantOptions _tenant;
///
/// Http上下文.
///
private readonly IHttpContextAccessor _httpContextAccessor;
///
/// 缓存管理.
///
private readonly ICacheManager _cacheManager;
///
/// 用户管理.
///
private readonly IUserManager _userManager;
///
/// 事件总线.
///
private readonly IEventPublisher _eventPublisher;
///
/// SqlSugarClient客户端.
///
private SqlSugarScope _sqlSugarClient;
private readonly ISendMessageService _sendMessageService;
private readonly IMHandler _imHandler;
private readonly BackgroundService _backgroundService; //added by ly on 20230916
private static CancellationTokenSource stopTimedTaskSvcCTS;
private static Dictionary> _fetchPropValue = new();
///
/// 初始化一个类型的新实例.
///
public OAuthService(
IGeneralCaptcha captchaHandler,
ISqlSugarRepository userRepository,
IModuleService moduleService,
IModuleButtonService moduleButtonService,
IModuleColumnService columnService,
IModuleDataAuthorizeSchemeService moduleDataAuthorizeSchemeService,
IModuleFormService formService,
ISysConfigService sysConfigService,
ISocialsUserService socialsUserService,
ISendMessageService sendMessageService,
IOptions connectionOptions,
IOptions tenantOptions,
ISqlSugarClient sqlSugarClient,
IHttpContextAccessor httpContextAccessor,
ICacheManager cacheManager,
IUserManager userManager,
IEventPublisher eventPublisher,
IMHandler imHandler)
{
_captchaHandler = captchaHandler;
_userRepository = userRepository;
_moduleService = moduleService;
_moduleButtonService = moduleButtonService;
_columnService = columnService;
_moduleDataAuthorizeSchemeService = moduleDataAuthorizeSchemeService;
_formService = formService;
_sysConfigService = sysConfigService;
_socialsUserService = socialsUserService;
_sendMessageService = sendMessageService;
_connectionStrings = connectionOptions.Value;
_tenant = tenantOptions.Value;
_sqlSugarClient = (SqlSugarScope)sqlSugarClient;
_httpContextAccessor = httpContextAccessor;
_cacheManager = cacheManager;
_userManager = userManager;
_eventPublisher = eventPublisher;
_imHandler = imHandler;
}
#region Get
///
/// 获取图形验证码.
///
/// 验证码长度.
/// 时间戳.
///
[HttpGet("ImageCode/{codeLength}/{timestamp}")]
[AllowAnonymous]
[IgnoreLog]
[NonUnify]
public async Task GetCode(int codeLength, string timestamp)
{
return new FileContentResult(await _captchaHandler.CreateCaptchaImage(timestamp, 120, 40, codeLength > 0 ? codeLength : 4), "image/jpeg");
}
///
/// 首次登录 根据账号获取数据库配置.
///
/// 账号.
[HttpGet("getConfig/{account}")]
[AllowAnonymous]
[IgnoreLog]
public async Task 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>();
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();
var sysConfigData = await _sqlSugarClient.Queryable()
.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();
// 返回给前端 是否开启验证码 和 验证码长度
return new { enableVerificationCode = sysConfig.enableVerificationCode, verificationCodeNumber = sysConfig.verificationCodeNumber > 0 ? sysConfig.verificationCodeNumber : 4 };
}
///
/// 获取当前登录用户信息.
///
/// Web和App
///
[HttpGet("CurrentUser")]
public async Task GetCurrentUser(string type)
{
if (type.IsNullOrEmpty()) type = "Web"; // 默认为Web端菜单目录
var userId = _userManager.UserId;
//modify by ly on 20230918 登录成功后启动定时服务
/*if (!userId.IsNullOrWhiteSpace())
{
if (!_fetchPropValue.TryGetValue("IsStarted", out var action))
{
var isStartedProp = _backgroundService.GetType().GetProperty("IsStarted");
var paramExp = Expression.Parameter(typeof(BackgroundService), "_backgroundSvc");
var propExp = Expression.Property(Expression.ConvertChecked(paramExp, isStartedProp.DeclaringType), isStartedProp);
var body = Expression.Lambda>(propExp, paramExp);
action = body.Compile();
_fetchPropValue["IsStarted"] = action;
}
if (!action?.Invoke(_backgroundService) ?? false)
{
stopTimedTaskSvcCTS = new();
try
{
_backgroundService.StartAsync(stopTimedTaskSvcCTS.Token); //此处不阻塞
}
catch (TaskCanceledException)
{
}
}
}*/
var loginOutput = new CurrentUserOutput();
loginOutput.userInfo = await _userManager.GetUserInfo();
// 菜单
loginOutput.menuList = await _moduleService.GetUserTreeModuleList(type);
// 子系统信息
loginOutput.userInfo.systemIds = await _userRepository.AsSugarClient().Queryable().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()
.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())
{
if (loginOutput.userInfo.systemIds.Any())
{
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();
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>();
permissionModel.column = currentUserModel.columnList.FindAll(t => t.moduleId.Equals(menu.id)).Adapt>();
permissionModel.form = currentUserModel.formList.FindAll(t => t.moduleId.Equals(menu.id)).Adapt>();
permissionModel.resource = currentUserModel.resourceList.FindAll(t => t.moduleId.Equals(menu.id)).Adapt>();
permissionList.Add(permissionModel);
});
loginOutput.permissionList = permissionList;
// 系统+菜单树
loginOutput.routerList = new List();
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();
return loginOutput;
}
///
/// 退出.
///
///
[HttpGet("Logout")]
public async Task Logout([FromQuery] string ticket)
{
//modify by ly on 20230918
/* stopTimedTaskSvcCTS ??= new();
await _backgroundService.StopAsync(stopTimedTaskSvcCTS.Token);
stopTimedTaskSvcCTS.Cancel();
*/ //stopTimedTaskSvcCTS.Dispose();
UserManager.AsscessToken = string.Empty;
var tenantId = _userManager.TenantId ?? "default";
var userId = _userManager.UserId ?? "admim";
var httpContext = _httpContextAccessor.HttpContext;
httpContext.SignoutToSwagger();
// 清除IM中的webSocket
var list = await GetOnlineUserList(tenantId);
if (list != null)
{
var onlineUser = list.Find(it => it.tenantId == tenantId && it.userId == userId);
if (onlineUser != null)
{
list.RemoveAll((x) => x.connectionId == onlineUser.connectionId);
await SetOnlineUserList(list, tenantId);
}
}
await DelUserInfo(tenantId, userId);
}
#endregion
#region POST
///
/// 用户登录.
///
/// 登录输入参数.
///
[HttpPost("Login")]
[Consumes("application/x-www-form-urlencoded")]
[AllowAnonymous]
[IgnoreLog]
public async Task 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>();
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);
}
}
if (!"default".Equals(tenantId) && _tenant.MultiTenancyType.Equals("COLUMN"))
{
_sqlSugarClient.QueryFilter.AddTableFilter(it => it.TenantId == tenantId);
}
else
{
_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();
var sysConfigData = await _sqlSugarClient.Queryable().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();
// 开启验证码验证
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().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().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
{
{ ClaimConst.CLAINMUSERID, userAnyPwd.Id },
{ ClaimConst.CLAINMACCOUNT, userAnyPwd.Account },
{ ClaimConst.CLAINMREALNAME, userAnyPwd.RealName },
{ ClaimConst.CLAINMORGID, userAnyPwd.OrganizeId },
{ ClaimConst.CLAINMADMINISTRATOR, userAnyPwd.IsAdministrator },
{ ClaimConst.TENANTID, options.ConfigId },
{ ClaimConst.CONNECTIONCONFIG, options},
{ ClaimConst.SINGLELOGIN, (int)sysConfig.singleLogin },
{ ClaimConst.OnlineTicket, input.online_ticket },
{ ClaimConst.LOGINTYPE,input.login_type}
}, tokenTimeout);
//modify by ly on 20230804
UserManager.AsscessToken = accessToken;
//await _cacheManager.SetAsync("AsscessToken", accessToken, TimeSpan.FromMinutes(-1));
// 单点登录标识缓存
if (_oauthOptions.Enabled) _cacheManager.Set("OnlineTicket_" + input.online_ticket, options.ConfigId);
// 设置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(input.jnpf_ticket);
if (ticket.IsNotEmptyOrNull())
{
var socialsEntity = ticket.value.ToObject();
var sInfo = await _userRepository.AsSugarClient().Queryable().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().FirstAsync(x => x.Id.Equals(user.Id));
var param = socialsUserEntity.ToObject>();
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>();
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)
};
}
///
/// 锁屏解锁登录.
///
/// 登录输入参数.
///
[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);
}
///
/// 注销用户.
///
///
[HttpPost("logoutCurrentUser")]
[NonUnify]
public async Task 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 = "注销成功" };
}
///
/// 单点登录退出.
///
///
[HttpPost("Logout/auth2")]
[AllowAnonymous]
public async Task OnlineLogout()
{
var ticket = _httpContextAccessor.HttpContext.Request.Form["ticket"];
var tenantId = await _cacheManager.GetAsync("OnlineTicket_" + ticket);
if (ticket.IsNotEmptyOrNull())
{
await _cacheManager.DelAsync("OnlineTicket_" + ticket);
var userId = _userManager.GetAdminUserId();
var userOnlineList = new List();
userOnlineList = await GetOnlineUserList(tenantId);
var userOnline = userOnlineList.Find(x => x.onlineTicket.Equals(ticket));
if (userOnline != null)
{
userId = userOnline.userId;
await _imHandler.SendMessageAsync(userOnline.connectionId, new { method = "logout", msg = "此账号已在其他地方登陆" }.ToJsonString());
}
// 清除IM中的webSocket
if (userOnlineList != null)
{
var onlineUser = userOnlineList.Find(it => it.tenantId == tenantId && it.userId == userId);
if (onlineUser != null)
{
userOnlineList.RemoveAll((x) => x.connectionId == onlineUser.connectionId);
await SetOnlineUserList(userOnlineList, tenantId);
}
}
await DelUserInfo(tenantId, userId);
}
}
///
/// 密码过期提醒.
///
///
[HttpPost("updatePasswordMessage")]
public async Task PwdMessage()
{
var sysConfigInfo = await _sysConfigService.GetInfo();
// 密码修改时间.
var changePasswordDate = _userManager.User.ChangePasswordDate.IsNullOrEmpty() ? _userManager.User.CreatorTime : _userManager.User.ChangePasswordDate;
// 提醒时间
var remindDate = changePasswordDate.ParseToDateTime().AddDays(sysConfigInfo.updateCycle - sysConfigInfo.updateInAdvance);
if (sysConfigInfo.passwordIsUpdatedRegularly == 1 && remindDate < DateTime.Now)
{
await _sendMessageService.SendMessageSystem("XTXXTX001");
}
}
#endregion
#region PrivateMethod
///
/// 获取验证码.
///
/// 时间戳.
///
private async Task GetCode(string timestamp)
{
string cacheKey = string.Format("{0}{1}", CommonConst.CACHEKEYCODE, timestamp);
return await _cacheManager.GetAsync(cacheKey);
}
///
/// 判断app用户角色是否存在且有效.
///
///
///
private bool ExistRoleByApp(string roleIds)
{
if (roleIds.IsEmpty())
return false;
var roleIdList1 = roleIds.Split(",").ToList();
var roleIdList2 = _sqlSugarClient.Queryable().Where(x => x.DeleteMark == null && x.EnabledMark == 1).Select(x => x.Id).ToList();
return roleIdList1.Intersect(roleIdList2).ToList().Count > 0;
}
///
/// 记录密码错误次数.
///
/// 用户实体.
/// 系统配置输出.
///
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();
}
}
}
///
/// 获取在线用户列表.
///
///
private async Task> GetOnlineUserList(string tenantId)
{
string cacheKey = string.Format("{0}{1}", CommonConst.CACHEKEYONLINEUSER, tenantId);
return await _cacheManager.GetAsync>(cacheKey);
}
///
/// 保存在线用户列表.
///
/// 在线用户列表.
///
private async Task SetOnlineUserList(List onlineList, string tenantId)
{
string cacheKey = string.Format("{0}{1}", CommonConst.CACHEKEYONLINEUSER, tenantId);
return await _cacheManager.SetAsync(cacheKey, onlineList);
}
///
/// 删除用户登录信息缓存.
///
private async Task DelUserInfo(string tenantId, string userId)
{
string cacheKey = string.Format("{0}:{1}:{2}", tenantId, CommonConst.CACHEKEYUSER, userId);
return await _cacheManager.DelAsync(cacheKey);
}
///
/// 组装用户所有菜单.
///
///
///
private List GetUserAllMenu(List menuList)
{
var result = new List();
menuList.ForEach(item =>
{
var menu = item.Adapt();
if (menu.children != null && menu.children.Any())
{
menu.hasChildren = true;
menu.children = GetUserAllMenu(menu.children.Adapt>());
}
result.Add(menu);
});
return result;
}
#endregion
#region 第三方登录回调
///
/// 第三方登录回调.
///
///
[HttpGet("Login/socials")]
[AllowAnonymous]
[IgnoreLog]
[NonUnify]
public async Task 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>();
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();
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>();
if (resultObj["code"].ToString() != "200")
{
throw Oops.Oh(resultObj["msg"].ToString());
}
var ticket = _cacheManager.Get(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>>();
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>();
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("", resStr));
}
return resStr.ToObject>();
}
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>();
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(req.jnpf_ticket);
if (ticket == null && req.code.IsNullOrWhiteSpace()) Oops.Oh(ErrorCode.D1035);
var data = res.ToObject>();
if (data.ContainsKey("data"))
{
var socialsEntity = data["data"].ToObject();
// 接受CODE 进行登录
var sEntity = await _userRepository.AsSugarClient().Queryable().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>();
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("", result.ToJsonString()));
}
return res.ToObject>();
}
///
/// 多租户第三方登录回调.
///
///
[HttpPost("Login/socials")]
[Consumes("application/x-www-form-urlencoded")]
[AllowAnonymous]
[IgnoreLog]
public async Task 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>();
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;
}
///
/// 获取登录配置, 是否需要跳转、第三方登录信息.
///
[HttpGet("GetLoginConfig")]
[AllowAnonymous]
[IgnoreLog]
public dynamic GetSocialsLoginConfig()
{
var loginConfigModel = new SocialsLoginConfigModel();
if (_oauthOptions.Enabled)
{
var url = _oauthOptions.LoginPath + "/" + _oauthOptions.DefaultSSO;
loginConfigModel.redirect = true;
loginConfigModel.url = url;
loginConfigModel.ticketParams = CommonConst.PARAMS_JNPF_TICKET;
}
else
{
// 追加第三方登录配置
var loginList = _socialsUserService.GetLoginList(CommonConst.PARAMS_JNPF_TICKET.ToUpper());
if (loginList == null) return loginConfigModel;
if (loginList.Any())
{
loginConfigModel.socialsList = loginList.ToObject>();
loginConfigModel.redirect = false;
loginConfigModel.ticketParams = CommonConst.PARAMS_JNPF_TICKET;
}
}
return loginConfigModel;
}
///
/// 获取登录票据.
///
/// return {msg:有效期, data:票据}.
[HttpGet("getTicket")]
[AllowAnonymous]
[IgnoreLog]
public dynamic GetTicket()
{
SocialsLoginTicketModel ticketModel = new SocialsLoginTicketModel();
var curDate = DateTime.Now.AddMinutes(_oauthOptions.TicketTimeout); // 默认过期5分钟.
ticketModel.ticketTimeout = curDate.ParseToUnixTime();
var key = "SocialsLogin_" + SnowflakeIdHelper.NextId();
_cacheManager.Set(key, ticketModel.ToJsonString(), TimeSpan.FromMinutes(_oauthOptions.TicketTimeout));
return key;
}
///
/// 检测票据登录状态.
///
///
[HttpGet("getTicketStatus/{ticket}")]
[AllowAnonymous]
[IgnoreLog]
public dynamic GetTicketStatus(string ticket)
{
var ticketModel = _cacheManager.Get(ticket);
if (ticketModel == null)
{
ticketModel = new SocialsLoginTicketModel() { status = (int)SocialsLoginTicketStatus.Invalid };
}
return ticketModel;
}
#endregion
#region 单点登录.
///
/// 单点登录接口.
///
///
///
[HttpGet("Login/{type}")]
[AllowAnonymous]
[IgnoreLog]
[NonUnify]
public async Task LoginByType(string type, [FromQuery] Dictionary input)
{
#region Cas
//if (type.ToLower().Equals("cas"))
//{
// var ticket = input.ContainsKey(CommonConst.PARAMS_JNPF_TICKET) ? input[CommonConst.PARAMS_JNPF_TICKET].ToString() : string.Empty;
// var ticketModel = _cacheManager.Get(ticket);
// if (ticketModel == null) return "登录票据已失效";
// var casTicket = input.ContainsKey(CommonConst.CAS_Ticket) ? input[CommonConst.CAS_Ticket].ToString() : string.Empty;
// if (casTicket.IsNotEmptyOrNull())
// {
// }
// else
// {
// var loginUrl = _oauthOptions.SSO.Cas.ServerLoginUrl;
// //http://sso.maxkey.top:8527/sign/authz/cas/?service=http://sa-oauth-client.demo.maxkey.top:8002
// loginUrl = Extras.CollectiveOAuth.Utils.UrlBuilder.fromBaseUrl(loginUrl)
// .queryParam("service", _oauthOptions.LoginPath + "/cas")
// .queryParam(CommonConst.PARAMS_JNPF_TICKET, ticket)
// .build();
// _httpContextAccessor.HttpContext.Response.Redirect(loginUrl);
// }
//}
#endregion
if (type.ToLower().Equals("auth2"))
{
var ticket = string.Empty;
if (input.ContainsKey(CommonConst.PARAMS_JNPF_TICKET) && input[CommonConst.PARAMS_JNPF_TICKET].IsNotEmptyOrNull())
{
ticket = input[CommonConst.PARAMS_JNPF_TICKET];
var ticketModel = _cacheManager.Get(ticket);
if (ticketModel == null) return "登录票据已失效";
}
var code = input.ContainsKey(CommonConst.Code) ? input[CommonConst.Code] : string.Empty;
// 接受CODE 进行登录
if (code.IsNotEmptyOrNull())
{
try
{
await loginByCode(code, ticket);
}
catch (Exception e)
{
// 更新登录结果
return e.Message;
}
}
else
{
redirectLogin(ticket);
}
}
return null;
}
///
/// 跳转单点登录页面.
///
protected void redirectLogin(string ticket)
{
var loginUrl = _oauthOptions.SSO.Auth2.AuthorizeUrl;
var tmpAuthCallbackUrl = _oauthOptions.LoginPath + "/auth2";
//http://sso.maxkey.top:8527/sign/authz/oauth/v20/authorize?response_type=code&client_id=745057899234983936&redirect_uri=http://sa-oauth-client.demo.maxkey.top:8002/&scope=all
if (ticket.IsNotEmptyOrNull())
{
tmpAuthCallbackUrl = Extras.CollectiveOAuth.Utils.UrlBuilder.fromBaseUrl(tmpAuthCallbackUrl)
.queryParam(CommonConst.PARAMS_JNPF_TICKET, ticket)
.build();
}
loginUrl = Extras.CollectiveOAuth.Utils.UrlBuilder.fromBaseUrl(loginUrl)
.queryParam("response_type", CommonConst.Code)
.queryParam("client_id", _oauthOptions.SSO.Auth2.ClientId)
.queryParam("scope", "read")
.queryParam("redirect_uri", tmpAuthCallbackUrl)
.build();
_httpContextAccessor.HttpContext.Response.Redirect(loginUrl);
}
///
/// Oauth2登录.
///
///
///
protected async Task loginByCode(string code, string ticket)
{
var token = await getAccessToken(code);
var remoteUserInfo = await getRemoteInfo(token);
//var userId = remoteUserInfo.getOrDefault("accounts.username", remoteUserInfo["username"]).ToString();
var userId = remoteUserInfo.ContainsKey("accounts.username") ? remoteUserInfo["accounts.username"].ToString() : remoteUserInfo["username"].ToString();
var userAccount = string.Empty;
if (_tenant.MultiTenancy)
{
var instId = remoteUserInfo["institution"].ToString();
userAccount = instId + "@" + userId;
}
else
{
userAccount = userId;
}
// 登录账号
var loginInput = await GetUserInfoByUserAccount(userAccount);
loginInput.online_ticket = remoteUserInfo["online_ticket"].ToString();
var loginRes = await Login(loginInput);
var jnpfTicket = _cacheManager.Get(ticket);
if (jnpfTicket.IsNotEmptyOrNull())
{
// 修改 缓存 状态
jnpfTicket.status = (int)SocialsLoginTicketStatus.Success;
jnpfTicket.value = loginRes.token;
_cacheManager.Set(ticket, jnpfTicket.ToJsonString(), TimeSpan.FromMinutes(_oauthOptions.TicketTimeout));
}
else
{
var url = string.Format("{0}?token={1}&theme={2}", _oauthOptions.SucessFrontUrl, loginRes.token, loginRes.theme);
_httpContextAccessor.HttpContext.Response.Redirect(url);
}
}
///
/// 获取OAUTH2 AccessToken.
///
///
///
private async Task getAccessToken(string code)
{
var reqUrl = _oauthOptions.SSO.Auth2.AccessTokenUrl
.AddUrlQuery(string.Format("grant_type={0}", "authorization_code"))
.AddUrlQuery(string.Format("client_id={0}", _oauthOptions.SSO.Auth2.ClientId))
.AddUrlQuery(string.Format("client_secret={0}", _oauthOptions.SSO.Auth2.ClientSecret))
.AddUrlQuery(string.Format("redirect_uri={0}", _oauthOptions.LoginPath + "/auth2"))
.AddUrlQuery(string.Format("code={0}", code));
var response = await reqUrl.GetAsStringAsync();
Dictionary result = null;
try
{
result = response.ToObject>();
}
catch (Exception e)
{
// log.error("解析Auth2 access_token失败", e);
}
if (result == null || !result.ContainsKey("access_token"))
{
throw new Exception("Auth2: 获取access_token失败");
}
var access_token = result["access_token"].ToString();
// log.debug("Auth2 Token: {}", access_token);
return access_token;
}
///
/// 获取用户信息.
///
///
///
private async Task> getRemoteInfo(string access_token)
{
var reqUrl = _oauthOptions.SSO.Auth2.UserInfoUrl
.AddUrlQuery(string.Format("access_token={0}", access_token));
var response = await reqUrl.GetAsStringAsync();
Dictionary result = null;
try
{
// log.debug("Auth2 User: {}", response);
result = response.ToObject>();
}
catch (Exception e)
{
// log.error("解析Auth2 用户信息失败", e);
}
if (result == null || !result.ContainsKey("username"))
{
// log.error(response);
throw new Exception("Auth2: 获取远程用户信息失败");
}
return result;
}
private async Task GetUserInfoByUserAccount(string account)
{
ConnectionConfigOptions options = JNPFTenantExtensions.GetLinkToOrdinary(_connectionStrings.ConfigId, _connectionStrings.DBName);
UserAgent userAgent = new UserAgent(App.HttpContext);
if (_tenant.MultiTenancy)
{
// 分割账号
var tenantAccount = account.Split('@');
var tenantId = tenantAccount.FirstOrDefault();
if (tenantAccount.Length == 1)
account = "admin";
else
account = tenantAccount[1];
var interFace = string.Format("{0}{1}", _tenant.MultiTenancyDBInterFace, tenantId);
var response = await interFace.GetAsStringAsync();
var result = response.ToObject>();
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);
}
var userEntity = _sqlSugarClient.Queryable().Single(u => u.Account == account && u.DeleteMark == null);
return new LoginInput()
{
account = userEntity.Account,
password = userEntity.Password,
isSocialsLoginCallBack = true
};
}
#endregion
}