Merge branch 'lida_Dev' of https://github.com/AnonymousDotNet/BotSharp into lida_Dev
This commit is contained in:
commit
0ed663ea76
|
|
@ -71,7 +71,7 @@ public class SharpCacheAttribute : MoAttribute
|
|||
|
||||
private string GetCacheKey(SharpCacheSettings settings, MethodContext context)
|
||||
{
|
||||
var key = settings.Prefix + "-" + context.Method.Name;
|
||||
var key = settings.Prefix + ":" + context.Method.Name;
|
||||
foreach (var arg in context.Arguments)
|
||||
{
|
||||
if (arg is null)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public interface IBotSharpRepository
|
|||
User? GetAffiliateUserByPhone(string phone) => throw new NotImplementedException();
|
||||
User? GetUserById(string id) => throw new NotImplementedException();
|
||||
List<User> GetUserByIds(List<string> ids) => throw new NotImplementedException();
|
||||
User? GetUserByAffiliateId(string affiliateId) => throw new NotImplementedException();
|
||||
List<User> GetUsersByAffiliateId(string affiliateId) => throw new NotImplementedException();
|
||||
User? GetUserByUserName(string userName) => throw new NotImplementedException();
|
||||
void CreateUser(User user) => throw new NotImplementedException();
|
||||
void UpdateExistUser(string userId, User user) => throw new NotImplementedException();
|
||||
|
|
|
|||
|
|
@ -14,4 +14,7 @@ public interface IUserIdentity
|
|||
string UserLanguage { get; }
|
||||
string? Phone { get; }
|
||||
string? AffiliateId { get; }
|
||||
string? EmployeeId { get; }
|
||||
string Type { get; }
|
||||
string Role { get; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ public interface IUserService
|
|||
Task<User> CreateUser(User user);
|
||||
Task<Token> ActiveUser(UserActivationModel model);
|
||||
Task<Token?> GetAffiliateToken(string authorization);
|
||||
Task<Token?> GetAdminToken(string authorization);
|
||||
Task<Token?> GetToken(string authorization);
|
||||
Task<User> GetMyProfile();
|
||||
Task<bool> VerifyUserNameExisting(string userName);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ public class User
|
|||
public bool Verified { get; set; }
|
||||
public string? RegionCode { get; set; }
|
||||
public string? AffiliateId { get; set; }
|
||||
public string? EmployeeId { get; set; }
|
||||
public bool IsDisabled { get; set; }
|
||||
public DateTime UpdatedTime { get; set; } = DateTime.UtcNow;
|
||||
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
|
||||
|
|
|
|||
|
|
@ -31,9 +31,9 @@ public partial class FileRepository
|
|||
return Users.Where(x => ids.Contains(x.Id) || (x.ExternalId != null && ids.Contains(x.ExternalId)))?.ToList() ?? new List<User>();
|
||||
}
|
||||
|
||||
public User? GetUserByAffiliateId(string affiliateId)
|
||||
public List<User> GetUsersByAffiliateId(string affiliateId)
|
||||
{
|
||||
return Users.FirstOrDefault(x => x.AffiliateId == affiliateId);
|
||||
return Users.Where(x => x.AffiliateId == affiliateId).ToList();
|
||||
}
|
||||
|
||||
public User? GetUserByUserName(string userName = null)
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ public partial class RoutingService
|
|||
message.PostbackFunctionName = clonedMessage.PostbackFunctionName;
|
||||
message.CurrentAgentId = clonedMessage.CurrentAgentId;
|
||||
message.Content = clonedMessage.Content;
|
||||
message.Payload = clonedMessage.Payload;
|
||||
message.StopCompletion = clonedMessage.StopCompletion;
|
||||
message.RichContent = clonedMessage.RichContent;
|
||||
message.Data = clonedMessage.Data;
|
||||
|
|
|
|||
|
|
@ -72,4 +72,13 @@ public class UserIdentity : IUserIdentity
|
|||
|
||||
[JsonPropertyName("affiliateId")]
|
||||
public string? AffiliateId => _claims?.FirstOrDefault(x => x.Type == "affiliateId")?.Value;
|
||||
|
||||
[JsonPropertyName("employeeId")]
|
||||
public string? EmployeeId => _claims?.FirstOrDefault(x => x.Type == "employeeId")?.Value;
|
||||
|
||||
[JsonPropertyName("type")]
|
||||
public string? Type => _claims?.FirstOrDefault(x => x.Type == "type")?.Value;
|
||||
|
||||
[JsonPropertyName("role")]
|
||||
public string? Role => _claims?.FirstOrDefault(x => x.Type == ClaimTypes.Role)?.Value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,19 +145,14 @@ public class UserService : IUserService
|
|||
return true;
|
||||
}
|
||||
|
||||
public async Task<Token> GetAffiliateToken(string authorization)
|
||||
public async Task<Token?> GetAffiliateToken(string authorization)
|
||||
{
|
||||
var base64 = Encoding.UTF8.GetString(Convert.FromBase64String(authorization));
|
||||
var (id, password) = base64.SplitAsTuple(":");
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
var record = db.GetAffiliateUserByPhone(id);
|
||||
if (record == null)
|
||||
{
|
||||
record = db.GetUserByPhone(id);
|
||||
}
|
||||
|
||||
var isCanLoginAffiliateRoleType = record != null && !record.IsDisabled && record.Type != UserType.Client;
|
||||
if (!isCanLoginAffiliateRoleType)
|
||||
var isCanLogin = record != null && !record.IsDisabled && record.Type == UserType.Affiliate;
|
||||
if (!isCanLogin)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
|
@ -167,6 +162,39 @@ public class UserService : IUserService
|
|||
return default;
|
||||
}
|
||||
|
||||
var (token, jwt) = BuildToken(record);
|
||||
|
||||
return await Task.FromResult(token);
|
||||
}
|
||||
|
||||
public async Task<Token?> GetAdminToken(string authorization)
|
||||
{
|
||||
var base64 = Encoding.UTF8.GetString(Convert.FromBase64String(authorization));
|
||||
var (id, password) = base64.SplitAsTuple(":");
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
var record = db.GetUserByPhone(id);
|
||||
var isCanLogin = record != null && !record.IsDisabled
|
||||
&& record.Type == UserType.Internal && new List<string>
|
||||
{
|
||||
UserRole.Root,UserRole.Admin
|
||||
}.Contains(record.Role);
|
||||
if (!isCanLogin)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
if (Utilities.HashTextMd5($"{password}{record.Salt}") != record.Password)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
var (token, jwt) = BuildToken(record);
|
||||
|
||||
return await Task.FromResult(token);
|
||||
}
|
||||
|
||||
private (Token, JwtSecurityToken) BuildToken(User record)
|
||||
{
|
||||
var accessToken = GenerateJwtToken(record);
|
||||
var jwt = new JwtSecurityTokenHandler().ReadJwtToken(accessToken);
|
||||
var token = new Token
|
||||
|
|
@ -176,7 +204,7 @@ public class UserService : IUserService
|
|||
TokenType = "Bearer",
|
||||
Scope = "api"
|
||||
};
|
||||
return token;
|
||||
return (token, jwt);
|
||||
}
|
||||
|
||||
public async Task<Token?> GetToken(string authorization)
|
||||
|
|
@ -264,16 +292,7 @@ public class UserService : IUserService
|
|||
return default;
|
||||
}
|
||||
|
||||
var accessToken = GenerateJwtToken(record);
|
||||
var jwt = new JwtSecurityTokenHandler().ReadJwtToken(accessToken);
|
||||
var token = new Token
|
||||
{
|
||||
AccessToken = accessToken,
|
||||
ExpireTime = jwt.Payload.Exp.Value,
|
||||
TokenType = "Bearer",
|
||||
Scope = "api"
|
||||
};
|
||||
|
||||
var (token, jwt) = BuildToken(record);
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
hook.UserAuthenticated(jwt);
|
||||
|
|
@ -297,7 +316,8 @@ public class UserService : IUserService
|
|||
new Claim("role", user.Role ?? UserRole.User),
|
||||
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
|
||||
new Claim("phone", user.Phone ?? string.Empty),
|
||||
new Claim("affiliateId", user.AffiliateId ?? string.Empty)
|
||||
new Claim("affiliateId", user.AffiliateId ?? string.Empty),
|
||||
new Claim("employeeId", user.EmployeeId ?? string.Empty)
|
||||
};
|
||||
|
||||
var validators = _services.GetServices<IAuthenticationHook>();
|
||||
|
|
@ -340,7 +360,7 @@ public class UserService : IUserService
|
|||
|
||||
private string GetUserTokenExpiresCacheKey(string userId)
|
||||
{
|
||||
return $"user_{userId}_token_expires";
|
||||
return $"user:{userId}_token_expires";
|
||||
}
|
||||
|
||||
public async Task<DateTime> GetUserTokenExpires()
|
||||
|
|
|
|||
|
|
@ -1,80 +1,78 @@
|
|||
using BotSharp.Abstraction.Users.Settings;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
|
||||
namespace BotSharp.OpenAPI.Filters
|
||||
{
|
||||
public class UserSingleLoginFilter : IAuthorizationFilter
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
private readonly IServiceProvider _services;
|
||||
namespace BotSharp.OpenAPI.Filters;
|
||||
|
||||
public UserSingleLoginFilter(IUserService userService, IServiceProvider services)
|
||||
public class UserSingleLoginFilter : IAuthorizationFilter
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
private readonly IServiceProvider _services;
|
||||
|
||||
public UserSingleLoginFilter(IUserService userService, IServiceProvider services)
|
||||
{
|
||||
_userService = userService;
|
||||
_services = services;
|
||||
}
|
||||
|
||||
public void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
var isAllowAnonymous = context.ActionDescriptor.EndpointMetadata
|
||||
.Any(em => em.GetType() == typeof(AllowAnonymousAttribute));
|
||||
|
||||
if (isAllowAnonymous)
|
||||
{
|
||||
_userService = userService;
|
||||
_services = services;
|
||||
return;
|
||||
}
|
||||
|
||||
public void OnAuthorization(AuthorizationFilterContext context)
|
||||
var bearerToken = GetBearerToken(context);
|
||||
if (!string.IsNullOrWhiteSpace(bearerToken))
|
||||
{
|
||||
var isAllowAnonymous = context.ActionDescriptor.EndpointMetadata
|
||||
.Any(em => em.GetType() == typeof(AllowAnonymousAttribute));
|
||||
var config = _services.GetRequiredService<AccountSetting>();
|
||||
var token = GetJwtToken(bearerToken);
|
||||
|
||||
if (isAllowAnonymous)
|
||||
if (config.AllowMultipleDeviceLoginUserIds.Contains(token.Claims.First(x => x.Type == "nameid").Value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var bearerToken = GetBearerToken(context);
|
||||
if (!string.IsNullOrWhiteSpace(bearerToken))
|
||||
var validTo = token.ValidTo.ToLongTimeString();
|
||||
var currentExpires = GetUserExpires().ToLongTimeString();
|
||||
|
||||
if (validTo != currentExpires)
|
||||
{
|
||||
var config = _services.GetRequiredService<AccountSetting>();
|
||||
var token = GetJwtToken(bearerToken);
|
||||
|
||||
if (config.AllowMultipleDeviceLoginUserIds.Contains(token.Claims.First(x => x.Type == "nameid").Value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var validTo = token.ValidTo.ToLongTimeString();
|
||||
var currentExpires = GetUserExpires().ToLongTimeString();
|
||||
|
||||
if (validTo != currentExpires)
|
||||
{
|
||||
Serilog.Log.Warning($"Token expired. Token expires at {validTo}, current expires at {currentExpires}");
|
||||
// login confict
|
||||
context.Result = new ConflictResult();
|
||||
}
|
||||
Serilog.Log.Warning($"Token expired. Token expires at {validTo}, current expires at {currentExpires}");
|
||||
// login confict
|
||||
context.Result = new ConflictResult();
|
||||
}
|
||||
}
|
||||
|
||||
private string GetBearerToken(AuthorizationFilterContext context)
|
||||
{
|
||||
if (context.HttpContext.Request.Headers.TryGetValue(HeaderNames.Authorization, out var bearerToken)
|
||||
&& !string.IsNullOrWhiteSpace(bearerToken.ToString()))
|
||||
{
|
||||
var tokenType = bearerToken.ToString().Split(" ").First();
|
||||
if (tokenType == JwtBearerDefaults.AuthenticationScheme)
|
||||
{
|
||||
return bearerToken.ToString().Split(" ").Last();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private JwtSecurityToken GetJwtToken(string jwtToken)
|
||||
{
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
var token = handler.ReadJwtToken(jwtToken);
|
||||
return token;
|
||||
}
|
||||
|
||||
private DateTime GetUserExpires()
|
||||
{
|
||||
return _userService.GetUserTokenExpires().GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
|
||||
private string GetBearerToken(AuthorizationFilterContext context)
|
||||
{
|
||||
if (context.HttpContext.Request.Headers.TryGetValue(HeaderNames.Authorization, out var bearerToken)
|
||||
&& !string.IsNullOrWhiteSpace(bearerToken.ToString()))
|
||||
{
|
||||
var tokenType = bearerToken.ToString().Split(" ").First();
|
||||
if (tokenType == JwtBearerDefaults.AuthenticationScheme)
|
||||
{
|
||||
return bearerToken.ToString().Split(" ").Last();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private JwtSecurityToken GetJwtToken(string jwtToken)
|
||||
{
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
var token = handler.ReadJwtToken(jwtToken);
|
||||
return token;
|
||||
}
|
||||
|
||||
private DateTime GetUserExpires()
|
||||
{
|
||||
return _userService.GetUserTokenExpires().GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ public class UserDocument : MongoBase
|
|||
public bool Verified { get; set; }
|
||||
public string? RegionCode { get; set; }
|
||||
public string? AffiliateId { get; set; }
|
||||
public string? EmployeeId { get; set; }
|
||||
public bool IsDisabled { get; set; }
|
||||
public DateTime CreatedTime { get; set; }
|
||||
public DateTime UpdatedTime { get; set; }
|
||||
|
|
@ -41,6 +42,7 @@ public class UserDocument : MongoBase
|
|||
Type = Type,
|
||||
Role = Role,
|
||||
AffiliateId = AffiliateId,
|
||||
EmployeeId = EmployeeId,
|
||||
IsDisabled = IsDisabled,
|
||||
VerificationCode = VerificationCode,
|
||||
Verified = Verified,
|
||||
|
|
|
|||
|
|
@ -37,11 +37,11 @@ public partial class MongoRepository
|
|||
return users?.Any() == true ? users.Select(x => x.ToUser()).ToList() : new List<User>();
|
||||
}
|
||||
|
||||
public User? GetUserByAffiliateId(string affiliateId)
|
||||
public List<User> GetUsersByAffiliateId(string affiliateId)
|
||||
{
|
||||
var user = _dc.Users.AsQueryable()
|
||||
.FirstOrDefault(x => x.AffiliateId == affiliateId);
|
||||
return user != null ? user.ToUser() : null;
|
||||
var users = _dc.Users.AsQueryable()
|
||||
.Where(x => x.AffiliateId == affiliateId).ToList();
|
||||
return users?.Any() == true ? users.Select(x => x.ToUser()).ToList() : new List<User>();
|
||||
}
|
||||
|
||||
public User? GetUserByUserName(string userName)
|
||||
|
|
@ -72,6 +72,7 @@ public partial class MongoRepository
|
|||
Verified = user.Verified,
|
||||
RegionCode = user.RegionCode,
|
||||
AffiliateId = user.AffiliateId,
|
||||
EmployeeId = user.EmployeeId,
|
||||
IsDisabled = user.IsDisabled,
|
||||
CreatedTime = DateTime.UtcNow,
|
||||
UpdatedTime = DateTime.UtcNow
|
||||
|
|
|
|||
Loading…
Reference in a new issue