sync full source from private myoffice
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
namespace MyOffice.Web.Auth;
|
||||
|
||||
using Core.Extensions;
|
||||
using Core.Identity;
|
||||
using Data.Models.Users;
|
||||
using Data.Repositories.Users;
|
||||
using Identity.Domain;
|
||||
using Identity.ExternalProviders;
|
||||
using Identity.Repositories;
|
||||
using Microsoft.Extensions.Options;
|
||||
using OpenIddict.Abstractions;
|
||||
using OpenIddict.Server;
|
||||
using static OpenIddict.Abstractions.OpenIddictConstants;
|
||||
using static OpenIddict.Server.OpenIddictServerEvents;
|
||||
|
||||
public sealed class ExternalGrantHandler : IOpenIddictServerHandler<HandleTokenRequestContext>
|
||||
{
|
||||
private readonly AppUserManager _userManager;
|
||||
private readonly IUserExternalRepository _userExternalRepository;
|
||||
private readonly IEnumerable<IExternalProviderValidator> _externalProviderValidators;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public ExternalGrantHandler(
|
||||
AppUserManager userManager,
|
||||
IUserExternalRepository userExternalRepository,
|
||||
IEnumerable<IExternalProviderValidator> externalProviderValidators,
|
||||
IHttpContextAccessor httpContextAccessor
|
||||
)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_userExternalRepository = userExternalRepository;
|
||||
_externalProviderValidators = externalProviderValidators;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync(HandleTokenRequestContext context)
|
||||
{
|
||||
if (!string.Equals(context.Request.GrantType, OpenIddictAuthConstants.ExternalGrantType, StringComparison.Ordinal))
|
||||
return;
|
||||
|
||||
var provider = context.Request.GetParameter("provider")?.ToString();
|
||||
if (provider.IsMissing())
|
||||
{
|
||||
context.Reject(Errors.InvalidRequest, "The provider parameter is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
var validator = _externalProviderValidators.FirstOrDefault(x => x.Provider.EqualsIgnoreCase(provider));
|
||||
if (validator is null || !validator.IsConfigured)
|
||||
{
|
||||
context.Reject(Errors.InvalidRequest, $"Provider not supported: {provider}");
|
||||
return;
|
||||
}
|
||||
|
||||
var token = context.Request.GetParameter("token")?.ToString();
|
||||
if (token.IsMissing())
|
||||
{
|
||||
context.Reject(Errors.InvalidRequest, "The token parameter is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
var validationResult = await validator.ValidateAsync(token);
|
||||
if (!validationResult.IsSuccessed)
|
||||
{
|
||||
context.Reject(Errors.InvalidGrant, "Token not valid.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_httpContextAccessor.HttpContext?.User?.Identity?.IsAuthenticated == true)
|
||||
{
|
||||
context.Reject(Errors.InvalidGrant, "Authentication failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
var user = await _userManager.FindByEmailAsync(validationResult.Email!);
|
||||
if (user is null)
|
||||
{
|
||||
if (!validationResult.EmailVerified)
|
||||
{
|
||||
context.Reject(Errors.InvalidGrant, "Email not confirmed.");
|
||||
return;
|
||||
}
|
||||
|
||||
user = await CreateUserAsync(validationResult.Email!, validationResult.EmailVerified, validationResult.FullName);
|
||||
if (user is null)
|
||||
{
|
||||
context.Reject(Errors.InvalidGrant, "Unable to create user.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var externalLogin = await _userExternalRepository.GetByUserIdAsync(user.Id, provider)
|
||||
?? AddExternalLogin(user, validationResult.Email!, validationResult.ExternalId!, provider);
|
||||
|
||||
context.SignIn(OpenIddictClaimsHelper.CreatePrincipal(user, context.Request.GetScopes()));
|
||||
}
|
||||
|
||||
private async Task<ApplicationUser<Guid>?> CreateUserAsync(string email, bool isEmailConfirmed, string? fullName)
|
||||
{
|
||||
var user = new ApplicationUser<Guid>
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
UserName = email,
|
||||
Email = email,
|
||||
IsEmailConfirmed = isEmailConfirmed,
|
||||
FullName = fullName
|
||||
};
|
||||
|
||||
var password = "Qq1!_" + Guid.NewGuid();
|
||||
var result = await _userManager.CreateAsync(user, password);
|
||||
return result.Succeeded ? user : null;
|
||||
}
|
||||
|
||||
private UserExternal AddExternalLogin(
|
||||
ApplicationUser<Guid> user,
|
||||
string email,
|
||||
string externalId,
|
||||
string provider
|
||||
)
|
||||
{
|
||||
var existing = _userExternalRepository.GetByUserId(user.Id, provider);
|
||||
if (existing is not null)
|
||||
return existing;
|
||||
|
||||
var claim = new UserExternal
|
||||
{
|
||||
UserId = user.Id,
|
||||
CreatedOn = DateTime.UtcNow,
|
||||
Provider = provider.ToLower(),
|
||||
ExternalId = externalId,
|
||||
Email = email
|
||||
};
|
||||
_userExternalRepository.AddUserExternal(claim);
|
||||
|
||||
return claim;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user