[성현모] AuthApi 분리
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
@ -6,8 +6,32 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.18" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WebApi.Library.DBContext\WebApi.Library.DBContext.csproj" />
|
||||
<ProjectReference Include="..\WebApi.Library\WebApi.Library.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="SystemX.Core">
|
||||
<HintPath>..\..\DLL\SystemX.Core.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Model\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
146
Projects/WebApi/AuthApi/Controllers/AuthController.cs
Normal file
146
Projects/WebApi/AuthApi/Controllers/AuthController.cs
Normal file
@ -0,0 +1,146 @@
|
||||
using AuthApi.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using SystemX.Core;
|
||||
using SystemX.Core.Model.Auth;
|
||||
|
||||
namespace AuthApi.Controllers
|
||||
{
|
||||
[Tags("Auth")]
|
||||
[Route("api/auth")]
|
||||
[ApiController]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public class AuthController : CommonController
|
||||
{
|
||||
private readonly AuthService _authService;
|
||||
|
||||
public AuthController(IServiceProvider serviceProvider, IHttpContextAccessor httpContextAccessor,
|
||||
AuthService authService)
|
||||
: base(serviceProvider, httpContextAccessor)
|
||||
{
|
||||
_authService = authService;
|
||||
}
|
||||
|
||||
[HttpGet("/health")]
|
||||
public async Task<IResult> Health()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
return Results.Ok("Healthy");
|
||||
}
|
||||
|
||||
[HttpPost("regisger")]
|
||||
public async Task<IResult> Register([FromBody] RegisterModel request)
|
||||
{
|
||||
// Log4net.WriteLine(GetRequestLog(request).LogModelToString("Request Auth"), LogType.CONTROLLER);
|
||||
|
||||
RegisterResponseModel response = new RegisterResponseModel();
|
||||
|
||||
if (request?.UserID != null && request?.Password != null)
|
||||
{
|
||||
response = await _authService.CreateUser(request);
|
||||
}
|
||||
|
||||
// Log4net.WriteLine(GetResponseLog(response).LogModelToString("Response Auth"), LogType.CONTROLLER);
|
||||
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("login")]
|
||||
public async Task<IResult> Login([FromBody] LoginModel request)
|
||||
{
|
||||
// Log4net.WriteLine(GetRequestLog(request).LogModelToString("Request Auth"), LogType.CONTROLLER);
|
||||
|
||||
LoginResponseModel response = new LoginResponseModel();
|
||||
response.UserID = request.UserID;
|
||||
response.EC = ERROR_CODE.EC_USER_LOGIN_FAILED;
|
||||
|
||||
if (request.UserID != null && request.Password != null)
|
||||
{
|
||||
response = await _authService.SelectUser(request);
|
||||
|
||||
if (response.EC == ERROR_CODE.EC_OK)
|
||||
{
|
||||
double convertExpires = Convert.ToDouble(_configService?.GetConfig()?.Auth?.accessTokenExpires);
|
||||
|
||||
response.AccessToken = GenerateJwtToken(response);
|
||||
response.AccessTokenExpired = DateTime.UtcNow.AddMinutes(convertExpires).ToUnixTime();
|
||||
|
||||
response.RefreshToken = GenerateJwtToken(response, true);
|
||||
}
|
||||
|
||||
await _authService.UpdateLoginInfo(request, response.RefreshToken);
|
||||
}
|
||||
|
||||
// Log4net.WriteLine(GetResponseLog(response).LogModelToString("Response Auth"), LogType.CONTROLLER);
|
||||
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("logout")]
|
||||
public async Task<IResult> Logout([FromBody] LogoutModel request)
|
||||
{
|
||||
// Log4net.WriteLine(GetRequestLog(request).LogModelToString("Request Auth"), LogType.CONTROLLER);
|
||||
|
||||
var response = _authService.LogoutUser(request);
|
||||
await Task.CompletedTask;
|
||||
|
||||
// Log4net.WriteLine(GetResponseLog(response).LogModelToString("Response Auth"), LogType.CONTROLLER);
|
||||
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
[Authorize]
|
||||
[HttpPost("validate")]
|
||||
public ActionResult<string> Validate([FromBody] string authToken)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
private TokenValidationParameters GetValidationParameters()
|
||||
{
|
||||
return new TokenValidationParameters()
|
||||
{
|
||||
ValidateLifetime = true,
|
||||
ValidateAudience = true,
|
||||
ValidateIssuer = true,
|
||||
ValidIssuer = $"{_configService?.GetConfig()?.Auth?.issuer}",
|
||||
ValidAudience = $"{_configService?.GetConfig()?.Auth?.issuer}",
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes($"{_configService?.GetConfig()?.Auth?.accessTokenSecret}"))
|
||||
};
|
||||
}
|
||||
|
||||
private string GenerateJwtToken(LoginResponseModel loginResponseModel, bool isRefreshToken = false)
|
||||
{
|
||||
var claims = new[]
|
||||
{
|
||||
new Claim(ClaimTypes.Name, $"{loginResponseModel.UserID}"),
|
||||
new Claim(ClaimTypes.Role, $"{loginResponseModel.RoleName}"),
|
||||
};
|
||||
|
||||
string secret = $"{_configService?.GetConfig()?.Auth?.accessTokenSecret}";
|
||||
double convertExpires = Convert.ToDouble(_configService?.GetConfig()?.Auth?.accessTokenExpires);
|
||||
if (isRefreshToken == true)
|
||||
{
|
||||
secret = $"{_configService?.GetConfig()?.Auth?.refreshTokenSecret}";
|
||||
convertExpires = Convert.ToDouble(_configService?.GetConfig()?.Auth?.refreshTokenExpires);
|
||||
}
|
||||
|
||||
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
|
||||
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
||||
|
||||
var token = new JwtSecurityToken(
|
||||
issuer: $"{_configService?.GetConfig()?.Auth?.issuer}",
|
||||
audience: $"{_configService?.GetConfig()?.Auth?.audience}",
|
||||
claims: claims,
|
||||
expires: DateTime.UtcNow.AddMinutes(convertExpires),
|
||||
signingCredentials: creds
|
||||
);
|
||||
|
||||
return new JwtSecurityTokenHandler().WriteToken(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
59
Projects/WebApi/AuthApi/Controllers/CommonController.cs
Normal file
59
Projects/WebApi/AuthApi/Controllers/CommonController.cs
Normal file
@ -0,0 +1,59 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Runtime.CompilerServices;
|
||||
using SystemX.Core.Services;
|
||||
using WebApi.Library.Config;
|
||||
|
||||
namespace AuthApi.Controllers
|
||||
{
|
||||
public class CommonController : ControllerBase
|
||||
{
|
||||
public readonly IServiceProvider _serviceProvider;
|
||||
public readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public readonly ConfigService<WebApiConfig>? _configService;
|
||||
|
||||
protected static Guid guid { get; private set; } = Guid.NewGuid();
|
||||
|
||||
public CommonController(IServiceProvider serviceProvider, IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
//provider
|
||||
_serviceProvider = serviceProvider;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
|
||||
//service
|
||||
_configService = _serviceProvider.GetService<ConfigService<WebApiConfig>>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request 클라이언트 IP
|
||||
/// </summary>
|
||||
protected virtual string? GetClientIP()
|
||||
{
|
||||
return _httpContextAccessor?.HttpContext?.Connection?.RemoteIpAddress?.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request 클라이언트 Url
|
||||
/// </summary>
|
||||
protected virtual string? GetRequestUrl()
|
||||
{
|
||||
return _httpContextAccessor?.HttpContext?.Request?.Path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request 클라이언트 method: [GET] or [POST]
|
||||
/// </summary>
|
||||
protected virtual string? GetRequestMethod()
|
||||
{
|
||||
return _httpContextAccessor?.HttpContext?.Request?.Method;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 현재 Action(함수) 이름 가져오기
|
||||
/// </summary>
|
||||
protected virtual string GetMethodName([CallerMemberName] string callerMemberName = "")
|
||||
{
|
||||
return callerMemberName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace AuthApi.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class WeatherForecastController : ControllerBase
|
||||
{
|
||||
private static readonly string[] Summaries = new[]
|
||||
{
|
||||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
||||
};
|
||||
|
||||
private readonly ILogger<WeatherForecastController> _logger;
|
||||
|
||||
public WeatherForecastController(ILogger<WeatherForecastController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet(Name = "GetWeatherForecast")]
|
||||
public IEnumerable<WeatherForecast> Get()
|
||||
{
|
||||
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
||||
{
|
||||
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
|
||||
TemperatureC = Random.Shared.Next(-20, 55),
|
||||
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,25 +1,118 @@
|
||||
using AuthApi.Services;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
using SystemX.Core.Services;
|
||||
using WebApi.Library.Config;
|
||||
|
||||
string configDir = @"../../Config";
|
||||
string configFileName = "WebApi.AuthApi.Config.json";
|
||||
|
||||
//raed log4net configs
|
||||
if (Log4net.IsConfigLoad == true)
|
||||
{
|
||||
Log4net.WriteLine("Log4net Init Success");
|
||||
Log4net.AutoRemoveLog();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Log4net Init Failed");
|
||||
return;
|
||||
}
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
//singleton
|
||||
builder.Services.AddSingleton<ConfigService<WebApiConfig>>();
|
||||
builder.Services.AddScoped<AuthService>();
|
||||
|
||||
//scoped
|
||||
|
||||
builder.Services.AddControllers();
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
|
||||
//config preload, auth set
|
||||
ConfigService<WebApiConfig> preloadConfig = new ConfigService<WebApiConfig>();
|
||||
if (preloadConfig.OpenConfig($@"{configDir}/{configFileName}") == true)
|
||||
{
|
||||
var config = preloadConfig.GetConfig();
|
||||
|
||||
//auth
|
||||
builder.Services
|
||||
.AddAuthentication(option =>
|
||||
{
|
||||
option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
})
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = true,
|
||||
ValidateAudience = true,
|
||||
ValidateLifetime = true,
|
||||
ValidateIssuerSigningKey = true,
|
||||
ClockSkew = TimeSpan.Zero,
|
||||
ValidIssuer = $"{config?.Auth?.issuer}",
|
||||
ValidAudience = $"{config?.Auth?.audience}",
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes($"{config?.Auth?.accessTokenSecret}"))
|
||||
};
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Log4net.WriteLine("Config Preload Load Error.", LogType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
//read api config and set
|
||||
string serverUrl = string.Empty;
|
||||
var configService = app.Services.GetService<ConfigService<WebApiConfig>>();
|
||||
bool isIIS = false;
|
||||
|
||||
if (configService?.OpenConfig($@"{configDir}/{configFileName}") == true)
|
||||
{
|
||||
Log4net.WriteLine("WebApi Config Success.");
|
||||
var apiConfig = ConfigService<WebApiConfig>.Config;
|
||||
if (apiConfig != null)
|
||||
{
|
||||
serverUrl = $"{apiConfig?.Server?.Address}:{apiConfig?.Server?.Port}";
|
||||
isIIS = apiConfig!.Server.IIS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log4net.WriteLine("WebApi Config Error.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
Log4net.WriteLine($"IsDevelopment:{app.Environment.IsDevelopment()}");
|
||||
Log4net.WriteLine($"Swagger Url: {serverUrl}/swagger");
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
|
||||
app.UseAuthentication();
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
if (isIIS == true)
|
||||
{
|
||||
app.Run();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log4net.WriteLine($"Operation Url: {serverUrl}");
|
||||
app.Run($"{serverUrl}");
|
||||
}
|
||||
|
||||
263
Projects/WebApi/AuthApi/Services/AuthService.cs
Normal file
263
Projects/WebApi/AuthApi/Services/AuthService.cs
Normal file
@ -0,0 +1,263 @@
|
||||
using SystemX.Core.Model.Auth;
|
||||
using SystemX.Core.Services;
|
||||
using SystemX.Core;
|
||||
using WebApi.Library.Config;
|
||||
using SystemX.Core.Config.Model;
|
||||
using System.Data;
|
||||
using SystemX.Core.DB;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SystemX.Core.DB.DBContext.AccountDB.Context;
|
||||
using SystemX.Core.DB.DBContext.AccountDB.Tables;
|
||||
|
||||
namespace AuthApi.Services
|
||||
{
|
||||
public class AuthService
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IServiceScopeFactory _scopeFactory;
|
||||
private readonly ConfigService<WebApiConfig>? _configService;
|
||||
|
||||
private readonly DataBase? _accountDB;
|
||||
|
||||
private static List<LoginResponseModel> Session = new List<LoginResponseModel>();
|
||||
|
||||
public AuthService(IServiceProvider serviceProvider, IServiceScopeFactory scopeFactory, ConfigService<WebApiConfig> configSerice)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_configService = configSerice;
|
||||
_scopeFactory = scopeFactory;
|
||||
_accountDB = _configService?.GetConfig()?.DataBase?.Find(x => x.DBContext == "VpkiAccountDbContext");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// create new user
|
||||
/// </summary>
|
||||
public async Task<RegisterResponseModel> CreateUser(RegisterModel registerModel)
|
||||
{
|
||||
//response
|
||||
RegisterResponseModel response = new RegisterResponseModel();
|
||||
response.EC = ERROR_CODE.EC_USER_REGISTER_FAILED;
|
||||
response.UserID = registerModel.UserID;
|
||||
response.Role = registerModel.Role;
|
||||
response.RoleName = registerModel.Role.ToString();
|
||||
|
||||
//context
|
||||
using (var scope = _scopeFactory.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AccountDbContext>();
|
||||
if (context is not null)
|
||||
{
|
||||
var user = await context.TUsers.AsNoTracking().Where(x => x.CUserId.ToLower() == registerModel.UserID.ToLower()).ToListAsync();
|
||||
if (user?.Count <= 0)
|
||||
{
|
||||
string auid = Guid.NewGuid().ToString();
|
||||
//user
|
||||
TUser newUser = new TUser
|
||||
{
|
||||
CAuid = auid,
|
||||
CUserId = registerModel.UserID,
|
||||
CPasswordHashed = registerModel.Password,
|
||||
CCreateDateTime = DateTime.Now,
|
||||
CLastLoginDateTime = new DateTime()
|
||||
};
|
||||
//role
|
||||
TRole newUserRole = new TRole
|
||||
{
|
||||
CAuid = auid,
|
||||
CRoleId = Convert.ToByte(registerModel.Role),
|
||||
CRoleName = registerModel.Role.ToString()
|
||||
};
|
||||
|
||||
using (var transaction = await context.CreateTransactionAsync())
|
||||
{
|
||||
await context.AddAsync(newUser);
|
||||
await context.AddAsync(newUserRole);
|
||||
|
||||
var result = await context.CloseTransactionAsync(transaction);
|
||||
if (result == true)
|
||||
{
|
||||
response.EC = ERROR_CODE.EC_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// select user(login)
|
||||
/// </summary>
|
||||
public async Task<LoginResponseModel> SelectUser(LoginModel loginModel)
|
||||
{
|
||||
//response
|
||||
LoginResponseModel response = new LoginResponseModel();
|
||||
response.EC = ERROR_CODE.EC_USER_LOGIN_FAILED;
|
||||
response.UserID = loginModel.UserID;
|
||||
|
||||
//var session = Session.Find(x => x.UserID?.ToLower() == loginModel.UserID?.ToLower());
|
||||
//if (session?.AccessTokenExpired < DateTime.Now.ToUnixTime())
|
||||
//{
|
||||
// Session.Remove(session);
|
||||
//}
|
||||
|
||||
//기존 로그인 체크
|
||||
// if (Session.Exists(x => x.UserID == $"{loginModel.UserID?.ToLower()}") == false)
|
||||
{
|
||||
if (loginModel != null)
|
||||
{
|
||||
//context
|
||||
using (var scope = _scopeFactory.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AccountDbContext>();
|
||||
if (context is not null)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var transaction = await context.CreateTransactionAsync(IsolationLevel.ReadUncommitted))
|
||||
{
|
||||
//select user
|
||||
var selectUser = await context.TUsers.AsNoTracking().FirstOrDefaultAsync(x => x.CUserId.ToLower() == loginModel!.UserID!.ToLower());
|
||||
if (selectUser is not null)
|
||||
{
|
||||
if (selectUser.CPasswordHashed == loginModel?.Password)
|
||||
{
|
||||
//select role
|
||||
var selectRole = await context.TRoles.FindAsync(selectUser.CAuid);
|
||||
if (selectRole != null)
|
||||
{
|
||||
response.Role = (UserRole)Enum.Parse(typeof(UserRole), selectRole.CRoleId.ToString());
|
||||
response.RoleName = selectRole.CRoleName;
|
||||
}
|
||||
|
||||
// Session.Add(response);
|
||||
|
||||
if (selectUser.CState == (byte)UserState.Active)
|
||||
{
|
||||
response.EC = ERROR_CODE.EC_OK;
|
||||
}
|
||||
else if (selectUser.CState == (byte)UserState.Inactive)
|
||||
{
|
||||
response.EC = ERROR_CODE.EC_USER_LOGIN_INAVTIVE;
|
||||
}
|
||||
else if (selectUser.CState == (byte)UserState.Block)
|
||||
{
|
||||
response.EC = ERROR_CODE.EC_USER_LOGIN_BLOCKED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
response.EC = ERROR_CODE.EC_USER_LOGIN_INVALID_PASSWORD;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
response.EC = ERROR_CODE.EC_USER_LOGIN_NOT_EXIST;
|
||||
Log4net.WriteLine($"{response.EC}", LogType.Error);
|
||||
}
|
||||
await context.CloseTransactionAsync(transaction);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log4net.WriteLine($"Select User Transaction Error", LogType.Exception);
|
||||
Log4net.WriteLine(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateLoginInfo(LoginModel loginModel, string? RefreshToken = "")
|
||||
{
|
||||
bool result = false;
|
||||
bool transactionResult = true;
|
||||
|
||||
using (var scope = _scopeFactory.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AccountDbContext>();
|
||||
if (context is not null)
|
||||
{
|
||||
var selectUser = await context.TUsers.AsNoTracking().FirstOrDefaultAsync(x => x.CUserId.ToLower() == loginModel!.UserID!.ToLower());
|
||||
if (selectUser is not null)
|
||||
{
|
||||
using (var transaction = await context.CreateTransactionAsync())
|
||||
{
|
||||
try
|
||||
{
|
||||
//user info
|
||||
selectUser.CLastLoginDateTime = DateTime.Now;
|
||||
context.Update(selectUser);
|
||||
|
||||
//refresh token
|
||||
var findRefreshToken = await context.TRefreshTokens.AsNoTracking().FirstOrDefaultAsync(x => x.CAuid == selectUser.CAuid);
|
||||
//null이면(없으면) add
|
||||
if (findRefreshToken == null)
|
||||
{
|
||||
await context.AddAsync(new TRefreshToken
|
||||
{
|
||||
CAuid = selectUser.CAuid,
|
||||
CRefreshToken = $"{RefreshToken}"
|
||||
});
|
||||
}
|
||||
//있으면 update
|
||||
else
|
||||
{
|
||||
findRefreshToken.CRefreshToken = $"{RefreshToken}";
|
||||
context.Update(findRefreshToken);
|
||||
}
|
||||
|
||||
//commit
|
||||
Log4net.WriteLine(findRefreshToken?.ToJson(), LogType.Debug);
|
||||
|
||||
result = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log4net.WriteLine(ex);
|
||||
}
|
||||
|
||||
transactionResult = await context.CloseTransactionAsync(transaction);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log4net.WriteLine($"Not Exist User {loginModel.UserID}", LogType.Error);
|
||||
}
|
||||
|
||||
//db error
|
||||
if (transactionResult == false)
|
||||
{
|
||||
Log4net.WriteLine($"Transaction Error", LogType.Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log4net.WriteLine($"Transaction Success", LogType.DB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public LogoutResponseModel LogoutUser(LogoutModel logoutModel)
|
||||
{
|
||||
LogoutResponseModel response = new LogoutResponseModel();
|
||||
response.UserID = logoutModel.UserID;
|
||||
response.EC = ERROR_CODE.EC_USER_LOGOUT_FAILED;
|
||||
|
||||
var session = Session.Find(x => x.UserID?.ToLower() == logoutModel?.UserID?.ToLower());
|
||||
if (session != null)
|
||||
{
|
||||
Session.Remove(session);
|
||||
response.EC = ERROR_CODE.EC_OK;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
namespace AuthApi
|
||||
{
|
||||
public class WeatherForecast
|
||||
{
|
||||
public DateOnly Date { get; set; }
|
||||
|
||||
public int TemperatureC { get; set; }
|
||||
|
||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||
|
||||
public string? Summary { get; set; }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using WebApi.Library.DBContext.DB.DBContext.AccountDB.Tables;
|
||||
|
||||
namespace WebApi.Library.DBContext.DB.DBContext.AccountDB.Context;
|
||||
|
||||
public partial class AccountDbContext : DbContext
|
||||
{
|
||||
public AccountDbContext()
|
||||
{
|
||||
}
|
||||
|
||||
public AccountDbContext(DbContextOptions<AccountDbContext> options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual DbSet<TRefreshToken> TRefreshTokens { get; set; }
|
||||
|
||||
public virtual DbSet<TRole> TRoles { get; set; }
|
||||
|
||||
public virtual DbSet<TUser> TUsers { get; set; }
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see https://go.microsoft.com/fwlink/?LinkId=723263.
|
||||
=> optionsBuilder.UseSqlServer("server=127.0.0.1; user id=SystemX; password=X; database=AccountDB; TrustServerCertificate=true;");
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<TRefreshToken>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.CAuid).HasName("PK__tRefresh__FBF0855465EB95AB");
|
||||
|
||||
entity.ToTable("tRefreshToken");
|
||||
|
||||
entity.Property(e => e.CAuid)
|
||||
.HasMaxLength(250)
|
||||
.HasColumnName("cAuid");
|
||||
entity.Property(e => e.CRefreshToken)
|
||||
.HasMaxLength(1000)
|
||||
.HasColumnName("cRefreshToken");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<TRole>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.CAuid).HasName("PK__tRole__FBF085540BB887D7");
|
||||
|
||||
entity.ToTable("tRole");
|
||||
|
||||
entity.Property(e => e.CAuid)
|
||||
.HasMaxLength(250)
|
||||
.HasColumnName("cAuid");
|
||||
entity.Property(e => e.CRoleId).HasColumnName("cRoleID");
|
||||
entity.Property(e => e.CRoleName)
|
||||
.HasMaxLength(20)
|
||||
.HasColumnName("cRoleName");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<TUser>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.CUserId).HasName("PK__tUser__A75DC19A721265FF");
|
||||
|
||||
entity.ToTable("tUser");
|
||||
|
||||
entity.Property(e => e.CUserId)
|
||||
.HasMaxLength(50)
|
||||
.HasColumnName("cUserID");
|
||||
entity.Property(e => e.CAuid)
|
||||
.HasMaxLength(250)
|
||||
.HasColumnName("cAuid");
|
||||
entity.Property(e => e.CCreateDateTime).HasColumnName("cCreateDateTime");
|
||||
entity.Property(e => e.CLastLoginDateTime).HasColumnName("cLastLoginDateTime");
|
||||
entity.Property(e => e.CPasswordHashed)
|
||||
.HasMaxLength(250)
|
||||
.HasColumnName("cPasswordHashed");
|
||||
entity.Property(e => e.CState).HasColumnName("cState");
|
||||
});
|
||||
|
||||
OnModelCreatingPartial(modelBuilder);
|
||||
}
|
||||
|
||||
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace WebApi.Library.DBContext.DB.DBContext.AccountDB.Tables;
|
||||
|
||||
public partial class TRefreshToken
|
||||
{
|
||||
public string CAuid { get; set; } = null!;
|
||||
|
||||
public string CRefreshToken { get; set; } = null!;
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace WebApi.Library.DBContext.DB.DBContext.AccountDB.Tables;
|
||||
|
||||
public partial class TRole
|
||||
{
|
||||
public string CAuid { get; set; } = null!;
|
||||
|
||||
public byte CRoleId { get; set; }
|
||||
|
||||
public string CRoleName { get; set; } = null!;
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace WebApi.Library.DBContext.DB.DBContext.AccountDB.Tables;
|
||||
|
||||
public partial class TUser
|
||||
{
|
||||
public string CUserId { get; set; } = null!;
|
||||
|
||||
public string CAuid { get; set; } = null!;
|
||||
|
||||
public string CPasswordHashed { get; set; } = null!;
|
||||
|
||||
public byte CState { get; set; }
|
||||
|
||||
public DateTime CCreateDateTime { get; set; }
|
||||
|
||||
public DateTime? CLastLoginDateTime { get; set; }
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
20
Projects/WebApi/WebApi.Library/Config/WebApiConfig.cs
Normal file
20
Projects/WebApi/WebApi.Library/Config/WebApiConfig.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using SystemX.Core.Config;
|
||||
using SystemX.Core.Config.Model;
|
||||
|
||||
namespace WebApi.Library.Config
|
||||
{
|
||||
public class WebApiConfig : WebCommonConfig
|
||||
{
|
||||
[JsonPropertyName("Auth")]
|
||||
public Auth? Auth { get; set; }
|
||||
|
||||
[JsonPropertyName("DataBase")]
|
||||
public List<DataBase>? DataBase { get; set; }
|
||||
}
|
||||
}
|
||||
23
Projects/WebApi/WebApi.Library/WebApi.Library.csproj
Normal file
23
Projects/WebApi/WebApi.Library/WebApi.Library.csproj
Normal file
@ -0,0 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="SystemX.Core">
|
||||
<HintPath>..\..\DLL\SystemX.Core.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@ -5,6 +5,15 @@ VisualStudioVersion = 17.9.34728.123
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AuthApi", "AuthApi\AuthApi.csproj", "{321DD194-9455-48F7-A0BE-EF6E95881714}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApi.Library", "WebApi.Library\WebApi.Library.csproj", "{1B109CFE-B860-4125-8F2B-06D95DE85E91}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApi.Library.DBContext", "WebApi.Library.DBContext\WebApi.Library.DBContext.csproj", "{92599205-8D5B-4630-B669-AA390193BC9E}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Config", "Config", "{C8D5274F-AC00-46C7-1F8D-E88E81087A52}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
..\Config\WebApi.AuthApi.Config.json = ..\Config\WebApi.AuthApi.Config.json
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -15,6 +24,14 @@ Global
|
||||
{321DD194-9455-48F7-A0BE-EF6E95881714}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{321DD194-9455-48F7-A0BE-EF6E95881714}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{321DD194-9455-48F7-A0BE-EF6E95881714}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1B109CFE-B860-4125-8F2B-06D95DE85E91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1B109CFE-B860-4125-8F2B-06D95DE85E91}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1B109CFE-B860-4125-8F2B-06D95DE85E91}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1B109CFE-B860-4125-8F2B-06D95DE85E91}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{92599205-8D5B-4630-B669-AA390193BC9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{92599205-8D5B-4630-B669-AA390193BC9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{92599205-8D5B-4630-B669-AA390193BC9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{92599205-8D5B-4630-B669-AA390193BC9E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
Reference in New Issue
Block a user