424 lines
17 KiB
C#
424 lines
17 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IdentityModel.Tokens.Jwt;
|
|
using System.Linq;
|
|
using System.Security.Claims;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Abp.Authorization;
|
|
using Abp.Authorization.Users;
|
|
using Abp.MultiTenancy;
|
|
using Abp.Runtime.Security;
|
|
using Abp.UI;
|
|
using BCS.BMC.Authentication.External;
|
|
using BCS.BMC.Authentication.JwtBearer;
|
|
using BCS.BMC.Authorization;
|
|
using BCS.BMC.Authorization.Users;
|
|
using BCS.BMC.Models.TokenAuth;
|
|
using BCS.BMC.MultiTenancy;
|
|
using BCS.BMC.CompanyMasters.Dto;
|
|
using System.Net;
|
|
using System.Net.Http;
|
|
using Newtonsoft.Json;
|
|
using System.Net.Http.Headers;
|
|
using BCS.BMC.BMC.CompanyMasters;
|
|
using Abp.Domain.Repositories;
|
|
using System.Runtime.Intrinsics.X86;
|
|
using System.Text;
|
|
using System.IO;
|
|
using Abp.AutoMapper;
|
|
using Abp.Domain.Entities;
|
|
using BCS.BMC.BMC.FirebaseCloudMessages;
|
|
|
|
namespace BCS.BMC.Controllers
|
|
{
|
|
[Route("api/[controller]/[action]")]
|
|
public class TokenAuthController : BMCControllerBase
|
|
{
|
|
private readonly LogInManager _logInManager;
|
|
private readonly ITenantCache _tenantCache;
|
|
private readonly AbpLoginResultTypeHelper _abpLoginResultTypeHelper;
|
|
private readonly TokenAuthConfiguration _configuration;
|
|
private readonly IExternalAuthConfiguration _externalAuthConfiguration;
|
|
private readonly IExternalAuthManager _externalAuthManager;
|
|
private readonly UserRegistrationManager _userRegistrationManager;
|
|
private readonly IRepository<CompanyMaster, int> _companyMaster;
|
|
private readonly IRepository<FirebaseToken, int> _firebaseToken;
|
|
ResponseMessageModel responsemessage = new ResponseMessageModel();
|
|
public TokenAuthController(
|
|
LogInManager logInManager,
|
|
ITenantCache tenantCache,
|
|
AbpLoginResultTypeHelper abpLoginResultTypeHelper,
|
|
TokenAuthConfiguration configuration,
|
|
IExternalAuthConfiguration externalAuthConfiguration,
|
|
IExternalAuthManager externalAuthManager,
|
|
UserRegistrationManager userRegistrationManager,
|
|
IRepository<CompanyMaster, int> companyMaster,
|
|
IRepository<FirebaseToken, int> firebaseToken)
|
|
{
|
|
_logInManager = logInManager;
|
|
_tenantCache = tenantCache;
|
|
_abpLoginResultTypeHelper = abpLoginResultTypeHelper;
|
|
_configuration = configuration;
|
|
_externalAuthConfiguration = externalAuthConfiguration;
|
|
_externalAuthManager = externalAuthManager;
|
|
_userRegistrationManager = userRegistrationManager;
|
|
_companyMaster = companyMaster;
|
|
_firebaseToken = firebaseToken;
|
|
}
|
|
|
|
[HttpPost]
|
|
public async Task<AuthenticateResultModel> Authenticate([FromBody] AuthenticateModel model)
|
|
{
|
|
var loginResult = await GetLoginResultAsync(
|
|
model.UserNameOrEmailAddress,
|
|
model.Password,
|
|
GetTenancyNameOrNull()
|
|
);
|
|
|
|
var accessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity));
|
|
|
|
return new AuthenticateResultModel
|
|
{
|
|
AccessToken = accessToken,
|
|
EncryptedAccessToken = GetEncryptedAccessToken(accessToken),
|
|
ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds,
|
|
UserId = loginResult.User.Id
|
|
};
|
|
}
|
|
|
|
[HttpGet]
|
|
public List<ExternalLoginProviderInfoModel> GetExternalAuthenticationProviders()
|
|
{
|
|
return ObjectMapper.Map<List<ExternalLoginProviderInfoModel>>(_externalAuthConfiguration.Providers);
|
|
}
|
|
|
|
[HttpPost]
|
|
public async Task<ExternalAuthenticateResultModel> ExternalAuthenticate([FromBody] ExternalAuthenticateModel model)
|
|
{
|
|
var externalUser = await GetExternalUserInfo(model);
|
|
|
|
var loginResult = await _logInManager.LoginAsync(new UserLoginInfo(model.AuthProvider, model.ProviderKey, model.AuthProvider), GetTenancyNameOrNull());
|
|
|
|
switch (loginResult.Result)
|
|
{
|
|
case AbpLoginResultType.Success:
|
|
{
|
|
var accessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity));
|
|
return new ExternalAuthenticateResultModel
|
|
{
|
|
AccessToken = accessToken,
|
|
EncryptedAccessToken = GetEncryptedAccessToken(accessToken),
|
|
ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds
|
|
};
|
|
}
|
|
case AbpLoginResultType.UnknownExternalLogin:
|
|
{
|
|
var newUser = await RegisterExternalUserAsync(externalUser);
|
|
if (!newUser.IsActive)
|
|
{
|
|
return new ExternalAuthenticateResultModel
|
|
{
|
|
WaitingForActivation = true
|
|
};
|
|
}
|
|
|
|
// Try to login again with newly registered user!
|
|
loginResult = await _logInManager.LoginAsync(new UserLoginInfo(model.AuthProvider, model.ProviderKey, model.AuthProvider), GetTenancyNameOrNull());
|
|
if (loginResult.Result != AbpLoginResultType.Success)
|
|
{
|
|
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(
|
|
loginResult.Result,
|
|
model.ProviderKey,
|
|
GetTenancyNameOrNull()
|
|
);
|
|
}
|
|
|
|
var accessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity));
|
|
|
|
return new ExternalAuthenticateResultModel
|
|
{
|
|
AccessToken = accessToken,
|
|
EncryptedAccessToken = GetEncryptedAccessToken(accessToken),
|
|
ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds
|
|
};
|
|
}
|
|
default:
|
|
{
|
|
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(
|
|
loginResult.Result,
|
|
model.ProviderKey,
|
|
GetTenancyNameOrNull()
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task<User> RegisterExternalUserAsync(ExternalAuthUserInfo externalUser)
|
|
{
|
|
var user = await _userRegistrationManager.RegisterAsync(
|
|
externalUser.Name,
|
|
externalUser.Surname,
|
|
externalUser.EmailAddress,
|
|
externalUser.EmailAddress,
|
|
Authorization.Users.User.CreateRandomPassword(),
|
|
true
|
|
);
|
|
|
|
user.Logins = new List<UserLogin>
|
|
{
|
|
new UserLogin
|
|
{
|
|
LoginProvider = externalUser.Provider,
|
|
ProviderKey = externalUser.ProviderKey,
|
|
TenantId = user.TenantId
|
|
}
|
|
};
|
|
|
|
await CurrentUnitOfWork.SaveChangesAsync();
|
|
|
|
return user;
|
|
}
|
|
|
|
private async Task<ExternalAuthUserInfo> GetExternalUserInfo(ExternalAuthenticateModel model)
|
|
{
|
|
var userInfo = await _externalAuthManager.GetUserInfo(model.AuthProvider, model.ProviderAccessCode);
|
|
if (userInfo.ProviderKey != model.ProviderKey)
|
|
{
|
|
throw new UserFriendlyException(L("CouldNotValidateExternalUser"));
|
|
}
|
|
|
|
return userInfo;
|
|
}
|
|
|
|
private string GetTenancyNameOrNull()
|
|
{
|
|
if (!AbpSession.TenantId.HasValue)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return _tenantCache.GetOrNull(AbpSession.TenantId.Value)?.TenancyName;
|
|
}
|
|
|
|
private async Task<AbpLoginResult<Tenant, User>> GetLoginResultAsync(string usernameOrEmailAddress, string password, string tenancyName)
|
|
{
|
|
var loginResult = await _logInManager.LoginAsync(usernameOrEmailAddress, password, tenancyName);
|
|
|
|
switch (loginResult.Result)
|
|
{
|
|
case AbpLoginResultType.Success:
|
|
return loginResult;
|
|
default:
|
|
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(loginResult.Result, usernameOrEmailAddress, tenancyName);
|
|
}
|
|
}
|
|
|
|
private string CreateAccessToken(IEnumerable<Claim> claims, TimeSpan? expiration = null)
|
|
{
|
|
var now = DateTime.UtcNow;
|
|
|
|
var jwtSecurityToken = new JwtSecurityToken(
|
|
issuer: _configuration.Issuer,
|
|
audience: _configuration.Audience,
|
|
claims: claims,
|
|
notBefore: now,
|
|
expires: now.Add(expiration ?? _configuration.Expiration),
|
|
signingCredentials: _configuration.SigningCredentials
|
|
);
|
|
|
|
return new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
|
|
}
|
|
|
|
private static List<Claim> CreateJwtClaims(ClaimsIdentity identity)
|
|
{
|
|
var claims = identity.Claims.ToList();
|
|
var nameIdClaim = claims.First(c => c.Type == ClaimTypes.NameIdentifier);
|
|
|
|
// Specifically add the jti (random nonce), iat (issued timestamp), and sub (subject/user) claims.
|
|
claims.AddRange(new[]
|
|
{
|
|
new Claim(JwtRegisteredClaimNames.Sub, nameIdClaim.Value),
|
|
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
|
|
new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.Now.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64)
|
|
});
|
|
|
|
return claims;
|
|
}
|
|
|
|
private string GetEncryptedAccessToken(string accessToken)
|
|
{
|
|
return SimpleStringCipher.Instance.Encrypt(accessToken);
|
|
}
|
|
|
|
[HttpPost]
|
|
public async Task<IActionResult> ValidateTenancy([FromBody] GetUrlDto input)
|
|
{
|
|
Uri uri = new Uri(input.InputUrl, UriKind.Absolute);
|
|
var domain = uri.Host;
|
|
|
|
if (string.IsNullOrWhiteSpace(input.InputUrl))
|
|
{
|
|
return BadRequest("Please Enter A Valid Url");
|
|
}
|
|
var company = await _companyMaster.FirstOrDefaultAsync(x => x.DomainName == domain);
|
|
if (company == null)
|
|
{
|
|
return BadRequest("Url Not Found");
|
|
}
|
|
var result = new
|
|
{
|
|
CompanyId = company.Id,
|
|
|
|
};
|
|
return Ok(result);
|
|
}
|
|
|
|
[HttpPost]
|
|
public async Task<IActionResult> Login([FromBody] LoginInputModel input)
|
|
{
|
|
var subDomainName = "";
|
|
var protocol = "";
|
|
if (string.IsNullOrWhiteSpace(input.CompanyUrl))
|
|
{
|
|
return BadRequest("Please Enter A Valid Url");
|
|
}
|
|
using (HttpClient client = new HttpClient())
|
|
{
|
|
Uri uri = new Uri(input.CompanyUrl);
|
|
var host = uri.Host;
|
|
protocol = uri.Scheme;
|
|
if (host.Split('.').Length > 2)
|
|
{
|
|
int lastIndex = host.LastIndexOf(".");
|
|
int index = host.LastIndexOf(".", lastIndex - 1);
|
|
var subdomain = host.Substring(0, index);
|
|
if (subdomain != "www")
|
|
{
|
|
subDomainName = subdomain;
|
|
}
|
|
}
|
|
|
|
var company = await _companyMaster.FirstOrDefaultAsync(x => x.DomainName == host);
|
|
if (company == null)
|
|
{
|
|
return BadRequest("Invalid Company Url");
|
|
}
|
|
|
|
// var baseUrl = uri + "api/BmcLogin";
|
|
var baseUrl = protocol + "://" + host + "/api/BmcLogin";
|
|
var data = new
|
|
{
|
|
usernameOrEmailAddress = input.UsernameOrEmailAddress,
|
|
password = input.Password
|
|
};
|
|
var requestJson = JsonConvert.SerializeObject(data);
|
|
var requestContent = new StringContent(requestJson.ToString());
|
|
requestContent.Headers.ContentType = new MediaTypeWithQualityHeaderValue("application/json");
|
|
HttpResponseMessage response = await client.PostAsync(baseUrl, requestContent);
|
|
|
|
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var responseStream = await response.Content.ReadAsStringAsync();
|
|
LoginOrRegisterResponseMessageModel result = JsonConvert.DeserializeObject<LoginOrRegisterResponseMessageModel>(responseStream);
|
|
|
|
|
|
var getTokenDetails = _firebaseToken.GetAllList().Where(x => x.HostName == host && x.UserId == int.Parse(result.result.userId)).FirstOrDefault();
|
|
if (getTokenDetails is null)
|
|
{
|
|
FirebaseToken entity = new FirebaseToken();
|
|
entity.UserId = int.Parse(result.result.userId);
|
|
entity.HostName = host;
|
|
entity.FcmToken = input.FcmToken;
|
|
await _firebaseToken.InsertAndGetIdAsync(entity);
|
|
}
|
|
if (getTokenDetails != null)
|
|
{
|
|
getTokenDetails.FcmToken = input.FcmToken;
|
|
|
|
await _firebaseToken.UpdateAsync(getTokenDetails);
|
|
}
|
|
return Ok(result);
|
|
}
|
|
else if (response.StatusCode == HttpStatusCode.InternalServerError)
|
|
{
|
|
var contents = await response.Content.ReadAsStringAsync();
|
|
ResponseMessageModel result = JsonConvert.DeserializeObject<ResponseMessageModel>(contents);
|
|
|
|
return BadRequest(result.error.message == "Login Failed" ? "Invalid Username Or Password" : result.error.message);
|
|
}
|
|
return Ok();
|
|
}
|
|
}
|
|
|
|
[HttpPost]
|
|
public async Task<IActionResult> Registration([FromBody] RegistrationInput input)
|
|
{
|
|
Uri uri = new Uri(input.CompanyUrl, UriKind.Absolute);
|
|
var domain = uri.Host;
|
|
|
|
if (string.IsNullOrWhiteSpace(input.CompanyUrl))
|
|
{
|
|
return BadRequest("Please Enter A Valid Url");
|
|
}
|
|
var company = await _companyMaster.FirstOrDefaultAsync(x => x.DomainName == domain);
|
|
if (company == null)
|
|
{
|
|
return BadRequest("Url Not Found");
|
|
}
|
|
using (HttpClient client = new HttpClient())
|
|
{
|
|
var baseUrl = input.CompanyUrl + "/api/services/bwac/employeeRegister/RegisterEmployeeAsNewUser";
|
|
|
|
var data = new
|
|
{
|
|
phoneNo = input.Phoneno,
|
|
userName = input.UserNameOrEmail,
|
|
password = input.Password
|
|
};
|
|
var requestJson = JsonConvert.SerializeObject(data);
|
|
var requestContent = new StringContent(requestJson.ToString());
|
|
requestContent.Headers.ContentType = new MediaTypeWithQualityHeaderValue("application/json");
|
|
HttpResponseMessage response = await client.PostAsync(baseUrl, requestContent);
|
|
|
|
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var responseStream = await response.Content.ReadAsStringAsync();
|
|
LoginOrRegisterResponseMessageModel result = JsonConvert.DeserializeObject<LoginOrRegisterResponseMessageModel>(responseStream);
|
|
return Ok(result);
|
|
}
|
|
else if (response.StatusCode == HttpStatusCode.InternalServerError)
|
|
{
|
|
var contents = await response.Content.ReadAsStringAsync();
|
|
ResponseMessageModel result = JsonConvert.DeserializeObject<ResponseMessageModel>(contents);
|
|
return BadRequest(result);
|
|
}
|
|
}
|
|
return BadRequest();
|
|
}
|
|
|
|
[HttpPost]
|
|
public async Task<IActionResult> DeleteRegisteredFcmToken([FromBody] FcmTokenDeleteInput input)
|
|
{
|
|
Uri uri = new Uri(input.HostName);
|
|
var host = uri.Host;
|
|
var getTokenDetails = _firebaseToken.GetAllList().Where(x => x.HostName == host && x.UserId == input.UserId).FirstOrDefault();
|
|
|
|
if (getTokenDetails != null)
|
|
{
|
|
FirebaseToken entity = new FirebaseToken();
|
|
getTokenDetails.FcmToken = null;
|
|
await _firebaseToken.UpdateAsync(getTokenDetails);
|
|
}
|
|
else
|
|
{
|
|
return BadRequest("logout failed");
|
|
}
|
|
return Ok("Success");
|
|
}
|
|
}
|
|
}
|