[성현모] AuthApi 분리
This commit is contained in:
35
Projects/Config/WebApi.AuthApi.Config.json
Normal file
35
Projects/Config/WebApi.AuthApi.Config.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"Server": {
|
||||||
|
"Address": "https://*",
|
||||||
|
"Port": 11000,
|
||||||
|
"IIS": false
|
||||||
|
},
|
||||||
|
"Auth": {
|
||||||
|
"issuer": "SystemX.WebApi.Auth",
|
||||||
|
"audience": "AuthApi",
|
||||||
|
"accessTokenSecret": "t6zdogyrT0U1bYw3gJvMm3JHmj2Iyawr7O2WKE2truX+MK0l/XNGmpU2ofagdUWBN4DxAUv7c8xSYVv/8abL6A==",
|
||||||
|
"accessTokenExpires": 1440, //minutes
|
||||||
|
"refreshTokenSecret": "1vVuoGqIqkStFI3QUXHMr0/yO1feLPnhqcfFGjZyk478+4WY7dhrUjCfVeWjmmSZYgb+rtP0X6ec+3iL35Yezw==",
|
||||||
|
"refreshTokenExpires": 1440 //minuts, 60*24 (1day)
|
||||||
|
},
|
||||||
|
"DataBase": [
|
||||||
|
{
|
||||||
|
"IP": "127.0.0.1",
|
||||||
|
"Port": 1433,
|
||||||
|
"DBName": "AccountDB",
|
||||||
|
"DBID": 1,
|
||||||
|
"DBContext": "AccountDB",
|
||||||
|
"UserID": "SystemX",
|
||||||
|
"Password": "X"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IP": "127.0.0.1",
|
||||||
|
"Port": 1433,
|
||||||
|
"DBName": "AccountDB_DEV",
|
||||||
|
"DBID": 2,
|
||||||
|
"DBContext": "AccountDB",
|
||||||
|
"UserID": "SystemX",
|
||||||
|
"Password": "X"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
85
Projects/Config/log4net.config
Normal file
85
Projects/Config/log4net.config
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<log4net>
|
||||||
|
<root>
|
||||||
|
<level value="ALL"/>
|
||||||
|
<appender-ref ref="Console"/>
|
||||||
|
<appender-ref ref="file"/>
|
||||||
|
<appender-ref ref="fatal_file"/>
|
||||||
|
</root>
|
||||||
|
|
||||||
|
<appender name="Console" type="log4net.Appender.ManagedColoredConsoleAppender">
|
||||||
|
<layout type="log4net.Layout.PatternLayout">
|
||||||
|
<conversionPattern value="[%date] [%thread] %-2level: %message%newline" />
|
||||||
|
</layout>
|
||||||
|
<mapping>
|
||||||
|
<level value="FATAL" />
|
||||||
|
<foreColor value="White" />
|
||||||
|
<backColor value="Red" />
|
||||||
|
</mapping>
|
||||||
|
<mapping>
|
||||||
|
<level value="ERROR" />
|
||||||
|
<foreColor value="Red" />
|
||||||
|
</mapping>
|
||||||
|
<mapping>
|
||||||
|
<level value="WARN" />
|
||||||
|
<foreColor value="Yellow" />
|
||||||
|
</mapping>
|
||||||
|
<mapping>
|
||||||
|
<level value="INFO" />
|
||||||
|
<foreColor value="Green" />
|
||||||
|
</mapping>
|
||||||
|
<mapping>
|
||||||
|
<level value="DEBUG" />
|
||||||
|
<foreColor value="Blue" />
|
||||||
|
</mapping>
|
||||||
|
|
||||||
|
<mapping>
|
||||||
|
<level value="EXCEPTION" />
|
||||||
|
<foreColor value="DarkRed" />
|
||||||
|
</mapping>
|
||||||
|
<mapping>
|
||||||
|
<level value="DB" />
|
||||||
|
<foreColor value="DarkMagenta" />
|
||||||
|
</mapping>
|
||||||
|
<mapping>
|
||||||
|
<level value="HTTP" />
|
||||||
|
<foreColor value="DarkYellow" />
|
||||||
|
</mapping>
|
||||||
|
<mapping>
|
||||||
|
<level value="SOCKET" />
|
||||||
|
<foreColor value="DarkCyan" />
|
||||||
|
</mapping>
|
||||||
|
<mapping>
|
||||||
|
<level value="CONTROLLER" />
|
||||||
|
<foreColor value="DarkGreen" />
|
||||||
|
</mapping>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="file" type="log4net.Appender.RollingFileAppender">
|
||||||
|
<file value="log/" />
|
||||||
|
<datepattern value="yyyy////MM////yyyy-MM-dd'.log'"/>
|
||||||
|
<appendToFile value="true" />
|
||||||
|
<rollingStyle value="Date" />
|
||||||
|
<staticLogFileName value="false" />
|
||||||
|
<layout type="log4net.Layout.PatternLayout">
|
||||||
|
<conversionPattern value="[%date] [%thread] %level %logger - %message%newline" />
|
||||||
|
</layout>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="fatal_file" type="log4net.Appender.RollingFileAppender">
|
||||||
|
<file value="log/" />
|
||||||
|
<datepattern value="yyyy////MM////yyyy-MM-dd'_fatal.log'"/>
|
||||||
|
<appendToFile value="true" />
|
||||||
|
<rollingStyle value="Date" />
|
||||||
|
<staticLogFileName value="false" />
|
||||||
|
<filter type="log4net.Filter.LevelRangeFilter">
|
||||||
|
<param name="LevelMin" value="FATAL" />
|
||||||
|
<param name="LevelMax" value="FATAL" />
|
||||||
|
</filter>
|
||||||
|
<layout type="log4net.Layout.PatternLayout">
|
||||||
|
<conversionPattern value="[%date] [%thread] %level %logger - %message%newline" />
|
||||||
|
</layout>
|
||||||
|
</appender>
|
||||||
|
</log4net>
|
||||||
|
</configuration>
|
||||||
Binary file not shown.
Binary file not shown.
@ -19,7 +19,7 @@ public partial class HubXContext : DbContext
|
|||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
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.
|
#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=VPKI; password=Kefico!@34; database=HubX; TrustServerCertificate=true;");
|
=> optionsBuilder.UseSqlServer("server=127.0.0.1; user id=alis; password=Kefico!@34; database=HubX; TrustServerCertificate=true;");
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using HubX.Library.Http.Packet;
|
using Azure.Core;
|
||||||
|
using HubX.Library.Http.Packet;
|
||||||
using HubX.Server.Services;
|
using HubX.Server.Services;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
@ -47,6 +48,30 @@ namespace HubX.Server.Controllers
|
|||||||
return Results.Ok(res);
|
return Results.Ok(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IResult> SelectUniqueKeyGet([FromQuery] string key)
|
||||||
|
{
|
||||||
|
var guid = Guid.NewGuid();
|
||||||
|
// Log4net.WriteLine($"[Requeust]({guid}) UniqueKey/SelectUniqueKey::{request.ToJson()}", LogType.CONTROLLER);
|
||||||
|
|
||||||
|
Response_SelectUniqueKy res = await _uniqueKeyService.Request_SelectUniqueKey(new Request_SelectUniqueKey { Identity = key } );
|
||||||
|
// Log4net.WriteLine($"[Response]({guid}) UniqueKey/SelectUniqueKey::{res.ToJson()}", LogType.CONTROLLER);
|
||||||
|
|
||||||
|
return Results.Ok(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IResult> SelectUniqueKeyGetAll()
|
||||||
|
{
|
||||||
|
var guid = Guid.NewGuid();
|
||||||
|
// Log4net.WriteLine($"[Requeust]({guid}) UniqueKey/SelectUniqueKey::{request.ToJson()}", LogType.CONTROLLER);
|
||||||
|
|
||||||
|
var res = await _uniqueKeyService.Request_SelectUniqueKeyAll();
|
||||||
|
// Log4net.WriteLine($"[Response]({guid}) UniqueKey/SelectUniqueKey::{res.ToJson()}", LogType.CONTROLLER);
|
||||||
|
|
||||||
|
return Results.Ok(res);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<IResult> UpdateUniqueKey(Request_UpdateUniqueKey request)
|
public async Task<IResult> UpdateUniqueKey(Request_UpdateUniqueKey request)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -4,6 +4,7 @@ using HubX.Library.Http.Packet;
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Identity.Client.Extensions.Msal;
|
using Microsoft.Identity.Client.Extensions.Msal;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using SystemX.Core.DB;
|
using SystemX.Core.DB;
|
||||||
@ -116,6 +117,33 @@ namespace HubX.Server.Services
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<List<TStorage>> Request_SelectUniqueKeyAll(string guid = "")
|
||||||
|
{
|
||||||
|
List<TStorage> result = new List<TStorage>();
|
||||||
|
using (var scope = _scopeFactory.CreateScope())
|
||||||
|
{
|
||||||
|
var context = scope.ServiceProvider.GetRequiredService<HubXContext>();
|
||||||
|
if (context != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var transaction = await context.CreateTransactionAsync(IsolationLevel.ReadUncommitted))
|
||||||
|
{
|
||||||
|
result = await context.TStorages.AsNoTracking().ToListAsync();
|
||||||
|
await context.CloseTransactionAsync(transaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log4net.WriteLine($"Select Unique Key Transaction Error::{guid}", LogType.Error);
|
||||||
|
Log4net.WriteLine(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<Response_UpdateUniqueKy> Request_UpdateUniqueKey(Request_UpdateUniqueKey request, string guid = "")
|
public async Task<Response_UpdateUniqueKy> Request_UpdateUniqueKey(Request_UpdateUniqueKey request, string guid = "")
|
||||||
{
|
{
|
||||||
Response_UpdateUniqueKy response = new Response_UpdateUniqueKy();
|
Response_UpdateUniqueKy response = new Response_UpdateUniqueKy();
|
||||||
|
|||||||
18
Projects/SystemX.Core/DBPatch/CreateAccountDB.bat
Normal file
18
Projects/SystemX.Core/DBPatch/CreateAccountDB.bat
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
@echo off
|
||||||
|
::log
|
||||||
|
IF NOT EXIST .\logs mkdir logs
|
||||||
|
|
||||||
|
::서버연결정보
|
||||||
|
SET ServerIP=127.0.0.1
|
||||||
|
SET ServerPort=1433
|
||||||
|
|
||||||
|
::DB 정보
|
||||||
|
SET UserID=SystemX
|
||||||
|
SET Passwd=X
|
||||||
|
SET DBName=AccountDB
|
||||||
|
|
||||||
|
::Default DB
|
||||||
|
@echo off
|
||||||
|
CD .\sqlScripts\
|
||||||
|
CALL _CreateScript.bat %ServerIP% %ServerPort% %UserID% %Passwd% %DBName%
|
||||||
|
CALL _CreateScript.bat %ServerIP% %ServerPort% %UserID% %Passwd% %DBName%_DEV
|
||||||
25
Projects/SystemX.Core/DBPatch/UpdateAccountDB.bat
Normal file
25
Projects/SystemX.Core/DBPatch/UpdateAccountDB.bat
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
@echo off
|
||||||
|
::log
|
||||||
|
IF NOT EXIST .\logs mkdir logs
|
||||||
|
|
||||||
|
::서버연결정보
|
||||||
|
SET ServerIP=127.0.0.1
|
||||||
|
SET ServerPort=1433
|
||||||
|
|
||||||
|
::DB 정보
|
||||||
|
SET UserID=SystemX
|
||||||
|
SET Passwd=X
|
||||||
|
SET DBName=AccountDB
|
||||||
|
|
||||||
|
::Update script 정보
|
||||||
|
SET Dacpac=.\dacpac\SystemX.DB.AccountDB.dacpac
|
||||||
|
SET OUTPUT=SystemX.DB.AccountDB_Update.sql
|
||||||
|
|
||||||
|
@echo off
|
||||||
|
::generate update script
|
||||||
|
CD .\sqlScripts\
|
||||||
|
CALL _UpdateScriptGenerate.bat %ServerIP% %ServerPort% %UserID% %Passwd% %DBName% %Dacpac% %OUTPUT%
|
||||||
|
|
||||||
|
::Default DB
|
||||||
|
CALL _UpdateAccountDB.bat %ServerIP% %ServerPort% %UserID% %Passwd% %DBName%
|
||||||
|
CALL _UpdateAccountDB.bat %ServerIP% %ServerPort% %UserID% %Passwd% %DBName%_DEV
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
@echo Create Admin Account Start
|
||||||
|
@echo off
|
||||||
|
|
||||||
|
SET SqlCmdOption=-E -C
|
||||||
|
sqlcmd %SqlCmdOption% -i %~dp0\sqlScripts\AdminAccount_Create.sql
|
||||||
|
if errorlevel 1 goto errexit
|
||||||
|
goto end
|
||||||
|
:errexit
|
||||||
|
echo DB Patch Fail
|
||||||
|
goto end
|
||||||
|
:end
|
||||||
|
@echo on
|
||||||
|
|
||||||
|
@echo Create Admin Account End
|
||||||
|
|
||||||
|
net stop /y MSSQLSERVER
|
||||||
|
net start /y MSSQLSERVER
|
||||||
|
|
||||||
|
pause
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
USE [master]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE LOGIN [SystemX] WITH PASSWORD=N'X', DEFAULT_DATABASE=[master], DEFAULT_LANGUAGE=[English], CHECK_POLICY=ON
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER LOGIN [SystemX] ENABLE
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER SERVER ROLE [sysadmin] ADD MEMBER [SystemX]
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER SERVER ROLE [securityadmin] ADD MEMBER [SystemX]
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER SERVER ROLE [serveradmin] ADD MEMBER [SystemX]
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER SERVER ROLE [setupadmin] ADD MEMBER [SystemX]
|
||||||
|
GO
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
USE [master]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE LOGIN [Alis] WITH PASSWORD=N'Kefico!@34', DEFAULT_DATABASE=[master], DEFAULT_LANGUAGE=[English], CHECK_POLICY=ON
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER LOGIN [Alis] ENABLE
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER SERVER ROLE [sysadmin] ADD MEMBER [Alis]
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER SERVER ROLE [securityadmin] ADD MEMBER [Alis]
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER SERVER ROLE [serveradmin] ADD MEMBER [Alis]
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER SERVER ROLE [setupadmin] ADD MEMBER [Alis]
|
||||||
|
GO
|
||||||
@ -0,0 +1,346 @@
|
|||||||
|
/*
|
||||||
|
SystemX.DB.AccountDB의 배포 스크립트
|
||||||
|
|
||||||
|
이 코드는 도구를 사용하여 생성되었습니다.
|
||||||
|
파일 내용을 변경하면 잘못된 동작이 발생할 수 있으며, 코드를 다시 생성하면
|
||||||
|
변경 내용이 손실됩니다.
|
||||||
|
*/
|
||||||
|
|
||||||
|
GO
|
||||||
|
SET ANSI_NULLS, ANSI_PADDING, ANSI_WARNINGS, ARITHABORT, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER ON;
|
||||||
|
|
||||||
|
SET NUMERIC_ROUNDABORT OFF;
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
/*
|
||||||
|
:setvar DatabaseName "SystemX.DB.AccountDB"
|
||||||
|
:setvar DefaultFilePrefix "SystemX.DB.AccountDB"
|
||||||
|
:setvar DefaultDataPath ""
|
||||||
|
:setvar DefaultLogPath ""
|
||||||
|
*/
|
||||||
|
|
||||||
|
GO
|
||||||
|
:on error exit
|
||||||
|
GO
|
||||||
|
/*
|
||||||
|
SQLCMD 모드가 지원되지 않으면 SQLCMD 모드를 검색하고 스크립트를 실행하지 않습니다.
|
||||||
|
SQLCMD 모드를 설정한 후에 이 스크립트를 다시 사용하려면 다음을 실행합니다.
|
||||||
|
SET NOEXEC OFF;
|
||||||
|
*/
|
||||||
|
:setvar __IsSqlCmdEnabled "True"
|
||||||
|
GO
|
||||||
|
IF N'$(__IsSqlCmdEnabled)' NOT LIKE N'True'
|
||||||
|
BEGIN
|
||||||
|
PRINT N'이 스크립트를 실행하려면 SQLCMD 모드를 사용하도록 설정해야 합니다.';
|
||||||
|
SET NOEXEC ON;
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
USE [master];
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
|
||||||
|
IF (DB_ID(N'$(DatabaseName)') IS NOT NULL)
|
||||||
|
BEGIN
|
||||||
|
ALTER DATABASE [$(DatabaseName)]
|
||||||
|
SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
|
||||||
|
DROP DATABASE [$(DatabaseName)];
|
||||||
|
END
|
||||||
|
|
||||||
|
GO
|
||||||
|
PRINT N'$(DatabaseName) 데이터베이스를 만드는 중...'
|
||||||
|
GO
|
||||||
|
CREATE DATABASE [$(DatabaseName)] COLLATE Korean_Wansung_CI_AS
|
||||||
|
GO
|
||||||
|
USE [$(DatabaseName)];
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
IF EXISTS (SELECT 1
|
||||||
|
FROM [master].[dbo].[sysdatabases]
|
||||||
|
WHERE [name] = N'$(DatabaseName)')
|
||||||
|
BEGIN
|
||||||
|
ALTER DATABASE [$(DatabaseName)]
|
||||||
|
SET ANSI_NULLS ON,
|
||||||
|
ANSI_PADDING ON,
|
||||||
|
ANSI_WARNINGS ON,
|
||||||
|
ARITHABORT ON,
|
||||||
|
CONCAT_NULL_YIELDS_NULL ON,
|
||||||
|
NUMERIC_ROUNDABORT OFF,
|
||||||
|
QUOTED_IDENTIFIER ON,
|
||||||
|
ANSI_NULL_DEFAULT ON,
|
||||||
|
CURSOR_DEFAULT LOCAL,
|
||||||
|
RECOVERY FULL,
|
||||||
|
CURSOR_CLOSE_ON_COMMIT OFF,
|
||||||
|
AUTO_CREATE_STATISTICS ON,
|
||||||
|
AUTO_SHRINK OFF,
|
||||||
|
AUTO_UPDATE_STATISTICS ON,
|
||||||
|
RECURSIVE_TRIGGERS OFF
|
||||||
|
WITH ROLLBACK IMMEDIATE;
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
IF EXISTS (SELECT 1
|
||||||
|
FROM [master].[dbo].[sysdatabases]
|
||||||
|
WHERE [name] = N'$(DatabaseName)')
|
||||||
|
BEGIN
|
||||||
|
ALTER DATABASE [$(DatabaseName)]
|
||||||
|
SET ALLOW_SNAPSHOT_ISOLATION OFF;
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
IF EXISTS (SELECT 1
|
||||||
|
FROM [master].[dbo].[sysdatabases]
|
||||||
|
WHERE [name] = N'$(DatabaseName)')
|
||||||
|
BEGIN
|
||||||
|
ALTER DATABASE [$(DatabaseName)]
|
||||||
|
SET READ_COMMITTED_SNAPSHOT OFF
|
||||||
|
WITH ROLLBACK IMMEDIATE;
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
IF EXISTS (SELECT 1
|
||||||
|
FROM [master].[dbo].[sysdatabases]
|
||||||
|
WHERE [name] = N'$(DatabaseName)')
|
||||||
|
BEGIN
|
||||||
|
ALTER DATABASE [$(DatabaseName)]
|
||||||
|
SET AUTO_UPDATE_STATISTICS_ASYNC OFF,
|
||||||
|
PAGE_VERIFY NONE,
|
||||||
|
DATE_CORRELATION_OPTIMIZATION OFF,
|
||||||
|
DISABLE_BROKER,
|
||||||
|
PARAMETERIZATION SIMPLE,
|
||||||
|
SUPPLEMENTAL_LOGGING OFF
|
||||||
|
WITH ROLLBACK IMMEDIATE;
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
IF IS_SRVROLEMEMBER(N'sysadmin') = 1
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (SELECT 1
|
||||||
|
FROM [master].[dbo].[sysdatabases]
|
||||||
|
WHERE [name] = N'$(DatabaseName)')
|
||||||
|
BEGIN
|
||||||
|
EXECUTE sp_executesql N'ALTER DATABASE [$(DatabaseName)]
|
||||||
|
SET TRUSTWORTHY OFF,
|
||||||
|
DB_CHAINING OFF
|
||||||
|
WITH ROLLBACK IMMEDIATE';
|
||||||
|
END
|
||||||
|
END
|
||||||
|
ELSE
|
||||||
|
BEGIN
|
||||||
|
PRINT N'데이터베이스 설정을 수정할 수 없습니다. 이러한 설정을 적용하려면 SysAdmin이어야 합니다.';
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
IF IS_SRVROLEMEMBER(N'sysadmin') = 1
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (SELECT 1
|
||||||
|
FROM [master].[dbo].[sysdatabases]
|
||||||
|
WHERE [name] = N'$(DatabaseName)')
|
||||||
|
BEGIN
|
||||||
|
EXECUTE sp_executesql N'ALTER DATABASE [$(DatabaseName)]
|
||||||
|
SET HONOR_BROKER_PRIORITY OFF
|
||||||
|
WITH ROLLBACK IMMEDIATE';
|
||||||
|
END
|
||||||
|
END
|
||||||
|
ELSE
|
||||||
|
BEGIN
|
||||||
|
PRINT N'데이터베이스 설정을 수정할 수 없습니다. 이러한 설정을 적용하려면 SysAdmin이어야 합니다.';
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
ALTER DATABASE [$(DatabaseName)]
|
||||||
|
SET TARGET_RECOVERY_TIME = 0 SECONDS
|
||||||
|
WITH ROLLBACK IMMEDIATE;
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
IF EXISTS (SELECT 1
|
||||||
|
FROM [master].[dbo].[sysdatabases]
|
||||||
|
WHERE [name] = N'$(DatabaseName)')
|
||||||
|
BEGIN
|
||||||
|
ALTER DATABASE [$(DatabaseName)]
|
||||||
|
SET FILESTREAM(NON_TRANSACTED_ACCESS = OFF),
|
||||||
|
CONTAINMENT = NONE
|
||||||
|
WITH ROLLBACK IMMEDIATE;
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
IF EXISTS (SELECT 1
|
||||||
|
FROM [master].[dbo].[sysdatabases]
|
||||||
|
WHERE [name] = N'$(DatabaseName)')
|
||||||
|
BEGIN
|
||||||
|
ALTER DATABASE [$(DatabaseName)]
|
||||||
|
SET AUTO_CREATE_STATISTICS ON(INCREMENTAL = OFF),
|
||||||
|
MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT = OFF,
|
||||||
|
DELAYED_DURABILITY = DISABLED
|
||||||
|
WITH ROLLBACK IMMEDIATE;
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
IF EXISTS (SELECT 1
|
||||||
|
FROM [master].[dbo].[sysdatabases]
|
||||||
|
WHERE [name] = N'$(DatabaseName)')
|
||||||
|
BEGIN
|
||||||
|
ALTER DATABASE [$(DatabaseName)]
|
||||||
|
SET QUERY_STORE (QUERY_CAPTURE_MODE = ALL, DATA_FLUSH_INTERVAL_SECONDS = 900, INTERVAL_LENGTH_MINUTES = 60, MAX_PLANS_PER_QUERY = 200, CLEANUP_POLICY = (STALE_QUERY_THRESHOLD_DAYS = 367), MAX_STORAGE_SIZE_MB = 100)
|
||||||
|
WITH ROLLBACK IMMEDIATE;
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
IF EXISTS (SELECT 1
|
||||||
|
FROM [master].[dbo].[sysdatabases]
|
||||||
|
WHERE [name] = N'$(DatabaseName)')
|
||||||
|
BEGIN
|
||||||
|
ALTER DATABASE [$(DatabaseName)]
|
||||||
|
SET QUERY_STORE = OFF
|
||||||
|
WITH ROLLBACK IMMEDIATE;
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
IF EXISTS (SELECT 1
|
||||||
|
FROM [master].[dbo].[sysdatabases]
|
||||||
|
WHERE [name] = N'$(DatabaseName)')
|
||||||
|
BEGIN
|
||||||
|
ALTER DATABASE SCOPED CONFIGURATION SET MAXDOP = 0;
|
||||||
|
ALTER DATABASE SCOPED CONFIGURATION FOR SECONDARY SET MAXDOP = PRIMARY;
|
||||||
|
ALTER DATABASE SCOPED CONFIGURATION SET LEGACY_CARDINALITY_ESTIMATION = OFF;
|
||||||
|
ALTER DATABASE SCOPED CONFIGURATION FOR SECONDARY SET LEGACY_CARDINALITY_ESTIMATION = PRIMARY;
|
||||||
|
ALTER DATABASE SCOPED CONFIGURATION SET PARAMETER_SNIFFING = ON;
|
||||||
|
ALTER DATABASE SCOPED CONFIGURATION FOR SECONDARY SET PARAMETER_SNIFFING = PRIMARY;
|
||||||
|
ALTER DATABASE SCOPED CONFIGURATION SET QUERY_OPTIMIZER_HOTFIXES = OFF;
|
||||||
|
ALTER DATABASE SCOPED CONFIGURATION FOR SECONDARY SET QUERY_OPTIMIZER_HOTFIXES = PRIMARY;
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
IF EXISTS (SELECT 1
|
||||||
|
FROM [master].[dbo].[sysdatabases]
|
||||||
|
WHERE [name] = N'$(DatabaseName)')
|
||||||
|
BEGIN
|
||||||
|
ALTER DATABASE [$(DatabaseName)]
|
||||||
|
SET TEMPORAL_HISTORY_RETENTION ON
|
||||||
|
WITH ROLLBACK IMMEDIATE;
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
IF fulltextserviceproperty(N'IsFulltextInstalled') = 1
|
||||||
|
EXECUTE sp_fulltext_database 'enable';
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
PRINT N'테이블 [dbo].[tRefreshToken]을(를) 만드는 중...';
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
CREATE TABLE [dbo].[tRefreshToken] (
|
||||||
|
[cAuid] NVARCHAR (250) NOT NULL,
|
||||||
|
[cRefreshToken] NVARCHAR (1000) NOT NULL,
|
||||||
|
PRIMARY KEY CLUSTERED ([cAuid] ASC)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
PRINT N'테이블 [dbo].[tRole]을(를) 만드는 중...';
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
CREATE TABLE [dbo].[tRole] (
|
||||||
|
[cAuid] NVARCHAR (250) NOT NULL,
|
||||||
|
[cRoleID] TINYINT NOT NULL,
|
||||||
|
[cRoleName] NVARCHAR (20) NOT NULL,
|
||||||
|
PRIMARY KEY CLUSTERED ([cAuid] ASC)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
PRINT N'테이블 [dbo].[tUser]을(를) 만드는 중...';
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
CREATE TABLE [dbo].[tUser] (
|
||||||
|
[cUserID] NVARCHAR (50) NOT NULL,
|
||||||
|
[cAuid] NVARCHAR (250) NOT NULL,
|
||||||
|
[cPasswordHashed] NVARCHAR (250) NOT NULL,
|
||||||
|
[cState] TINYINT NOT NULL,
|
||||||
|
[cCreateDateTime] DATETIME2 (7) NOT NULL,
|
||||||
|
[cLastLoginDateTime] DATETIME2 (7) NULL,
|
||||||
|
PRIMARY KEY CLUSTERED ([cUserID] ASC)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
/*
|
||||||
|
배포 후 스크립트 템플릿
|
||||||
|
--------------------------------------------------------------------------------------
|
||||||
|
이 파일에는 빌드 스크립트에 추가될 SQL 문이 있습니다.
|
||||||
|
SQLCMD 구문을 사용하여 파일을 배포 후 스크립트에 포함합니다.
|
||||||
|
예: :r .\myfile.sql
|
||||||
|
SQLCMD 구문을 사용하여 배포 후 스크립트의 변수를 참조합니다.
|
||||||
|
예: :setvar TableName MyTable
|
||||||
|
SELECT * FROM [$(TableName)]
|
||||||
|
--------------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM tUser WHERE cUserID = 'Alis')
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO tUser (cUserID, cAuid, cPasswordHashed, cState, cCreateDateTime, cLastLoginDateTime)
|
||||||
|
VALUES ('Alis', 'SuperUserAlis' ,'oKLQCdunc2kT5aAVfK+POKwd8R3p8OZvs/NATwpg4gM=' ,1 ,GETDATE(), GETDATE());
|
||||||
|
|
||||||
|
INSERT INTO tRole(cAuid, cRoleID, cRoleName)
|
||||||
|
VALUES ('SuperUserAlis','20','SuperUser');
|
||||||
|
END
|
||||||
|
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM tUser WHERE cUserID = 'SystemX')
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO tUser (cUserID, cAuid, cPasswordHashed, cState, cCreateDateTime, cLastLoginDateTime)
|
||||||
|
VALUES ('SystemX', 'SuperUserSystemX' ,'S2irOEf+2n1sYsH7y+6/o16rc1HtXnj03a3qXfZLgBU=' ,1 ,GETDATE(), GETDATE());
|
||||||
|
|
||||||
|
INSERT INTO tRole(cAuid, cRoleID, cRoleName)
|
||||||
|
VALUES ('SuperUserSystemX','20','SuperUser');
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
GO
|
||||||
|
DECLARE @VarDecimalSupported AS BIT;
|
||||||
|
|
||||||
|
SELECT @VarDecimalSupported = 0;
|
||||||
|
|
||||||
|
IF ((ServerProperty(N'EngineEdition') = 3)
|
||||||
|
AND (((@@microsoftversion / power(2, 24) = 9)
|
||||||
|
AND (@@microsoftversion & 0xffff >= 3024))
|
||||||
|
OR ((@@microsoftversion / power(2, 24) = 10)
|
||||||
|
AND (@@microsoftversion & 0xffff >= 1600))))
|
||||||
|
SELECT @VarDecimalSupported = 1;
|
||||||
|
|
||||||
|
IF (@VarDecimalSupported > 0)
|
||||||
|
BEGIN
|
||||||
|
EXECUTE sp_db_vardecimal_storage_format N'$(DatabaseName)', 'ON';
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
ALTER DATABASE [$(DatabaseName)]
|
||||||
|
SET MULTI_USER
|
||||||
|
WITH ROLLBACK IMMEDIATE;
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
|
PRINT N'업데이트가 완료되었습니다.';
|
||||||
|
|
||||||
|
|
||||||
|
GO
|
||||||
18
Projects/SystemX.Core/DBPatch/sqlScripts/_CreateScript.bat
Normal file
18
Projects/SystemX.Core/DBPatch/sqlScripts/_CreateScript.bat
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
SET ServerIP=%1
|
||||||
|
SET ServerPort=%2
|
||||||
|
SET UserID=%3
|
||||||
|
SET Passwd=%4
|
||||||
|
SET DBName=%5
|
||||||
|
|
||||||
|
SET SqlCmdOption=-C -U %UserID% -P %Passwd% -S %ServerIP%,%ServerPort% -f 65001 -o ..\logs\%DBName%.log
|
||||||
|
SET DatabaseName=%DBName%
|
||||||
|
sqlcmd %SqlCmdOption% -i .\SystemX.DB.AccountDB_Create.sql
|
||||||
|
if errorlevel 1 goto errexit
|
||||||
|
goto end
|
||||||
|
:errexit
|
||||||
|
echo DB Patch Failed
|
||||||
|
goto end
|
||||||
|
:end
|
||||||
|
@echo on
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
SET ServerIP=%1
|
||||||
|
SET ServerPort=%2
|
||||||
|
SET UserID=%3
|
||||||
|
SET Passwd=%4
|
||||||
|
SET DBName=%5
|
||||||
|
|
||||||
|
SET SqlCmdOption=-U %UserID% -P %Passwd% -S %ServerIP%,%ServerPort% -d %DBName% -o ..\logs\%DBName%.log
|
||||||
|
SET DatabaseName=%DBName%
|
||||||
|
sqlcmd %SqlCmdOption% -i .\SystemX.DB.AccountDB_Update.sql
|
||||||
|
|
||||||
|
if errorlevel 1 goto errexit
|
||||||
|
goto end
|
||||||
|
:errexit
|
||||||
|
echo DB Patch Fail
|
||||||
|
goto end
|
||||||
|
:end
|
||||||
|
@echo on
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
SET ServerIP=%1
|
||||||
|
SET ServerPort=%2
|
||||||
|
SET UserID=%3
|
||||||
|
SET Passwd=%4
|
||||||
|
SET DBName=%5
|
||||||
|
SET Dacpac=%6
|
||||||
|
SET OUTPUT=%7
|
||||||
|
|
||||||
|
::create update sql file
|
||||||
|
sqlpackage /Action:Script /SourceFile:%Dacpac% /TargetConnectionString:"server=%ServerIP%,%ServerPort%; user id=%UserID%; password=%Passwd%; database=%DBName%; TrustServerCertificate=true" /OutputPath:".\%OUTPUT%" /p:CommentOutSetVarDeclarations=True
|
||||||
Binary file not shown.
@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
|||||||
# Visual Studio Version 17
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 17.9.34728.123
|
VisualStudioVersion = 17.9.34728.123
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemX.Core", "SystemX.Core\SystemX.Core.csproj", "{F057A1E8-F5FF-4241-BEEA-1A57E971F379}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemX.Core", "SystemX.Core\SystemX.Core.csproj", "{F057A1E8-F5FF-4241-BEEA-1A57E971F379}"
|
||||||
|
EndProject
|
||||||
|
Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "SystemX.DB.AccountDB", "SystemX.DB.AccountDB\SystemX.DB.AccountDB.sqlproj", "{B44C85FA-BD31-419F-8481-477E166A5753}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@ -15,6 +17,12 @@ Global
|
|||||||
{F057A1E8-F5FF-4241-BEEA-1A57E971F379}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{F057A1E8-F5FF-4241-BEEA-1A57E971F379}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{F057A1E8-F5FF-4241-BEEA-1A57E971F379}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{F057A1E8-F5FF-4241-BEEA-1A57E971F379}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{F057A1E8-F5FF-4241-BEEA-1A57E971F379}.Release|Any CPU.Build.0 = Release|Any CPU
|
{F057A1E8-F5FF-4241-BEEA-1A57E971F379}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B44C85FA-BD31-419F-8481-477E166A5753}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B44C85FA-BD31-419F-8481-477E166A5753}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B44C85FA-BD31-419F-8481-477E166A5753}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||||
|
{B44C85FA-BD31-419F-8481-477E166A5753}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B44C85FA-BD31-419F-8481-477E166A5753}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B44C85FA-BD31-419F-8481-477E166A5753}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
33
Projects/SystemX.Core/SystemX.Core/Config/Model/Auth.cs
Normal file
33
Projects/SystemX.Core/SystemX.Core/Config/Model/Auth.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SystemX.Core.Config.Model
|
||||||
|
{
|
||||||
|
public class Auth
|
||||||
|
{
|
||||||
|
//jwt common
|
||||||
|
[JsonPropertyName("issuer")]
|
||||||
|
public string? issuer { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("audience")]
|
||||||
|
public string? audience { get; set; }
|
||||||
|
|
||||||
|
//access token
|
||||||
|
[JsonPropertyName("accessTokenSecret")]
|
||||||
|
public string? accessTokenSecret { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("accessTokenExpires")]
|
||||||
|
public uint? accessTokenExpires { get; set; }
|
||||||
|
|
||||||
|
//refresh token
|
||||||
|
[JsonPropertyName("refreshTokenSecret")]
|
||||||
|
public string? refreshTokenSecret { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("refreshTokenExpires")]
|
||||||
|
public uint? refreshTokenExpires { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,84 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using SystemX.Core.DB.DBContext.AccountDB.Tables;
|
||||||
|
|
||||||
|
namespace SystemX.Core.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 SystemX.Core.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 SystemX.Core.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 SystemX.Core.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; }
|
||||||
|
}
|
||||||
32
Projects/SystemX.Core/SystemX.Core/ERROR_CODE.cs
Normal file
32
Projects/SystemX.Core/SystemX.Core/ERROR_CODE.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SystemX.Core
|
||||||
|
{
|
||||||
|
public enum ERROR_CODE
|
||||||
|
{
|
||||||
|
//기본 에러
|
||||||
|
EC_NONE = 0,
|
||||||
|
EC_OK = 1,
|
||||||
|
|
||||||
|
//DB 관련 에러
|
||||||
|
EC_DEFAULT_ERROR = 1000,
|
||||||
|
EC_DATABASE_ERROR = 1001,
|
||||||
|
|
||||||
|
//유저 관련 에러
|
||||||
|
EC_USER_REGISTER_FAILED = 2000,
|
||||||
|
EC_USER_REGISTER_EXIST = 2001,
|
||||||
|
EC_USER_REGISTER_CONFIRM_PASSWORD_ERROR = 2002,
|
||||||
|
|
||||||
|
EC_USER_LOGIN_FAILED = 2100,
|
||||||
|
EC_USER_LOGIN_NOT_EXIST = 2101,
|
||||||
|
EC_USER_LOGIN_INVALID_PASSWORD = 2102,
|
||||||
|
EC_USER_LOGIN_INAVTIVE = 2103,
|
||||||
|
EC_USER_LOGIN_BLOCKED = 2104,
|
||||||
|
|
||||||
|
EC_USER_LOGOUT_FAILED = 2200
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -57,6 +57,8 @@ public static class Log4net
|
|||||||
|
|
||||||
public static bool IsConfigLoad { get; set; } = false;
|
public static bool IsConfigLoad { get; set; } = false;
|
||||||
|
|
||||||
|
public static string Log4netConfigPath { get; } = @"../../Config/log4net.config";
|
||||||
|
|
||||||
//로그 사용여부
|
//로그 사용여부
|
||||||
public static bool IsDebugEnabled { get; set; } = true;
|
public static bool IsDebugEnabled { get; set; } = true;
|
||||||
public static bool IsDBEnabled { get; set; } = true;
|
public static bool IsDBEnabled { get; set; } = true;
|
||||||
@ -70,7 +72,7 @@ public static class Log4net
|
|||||||
|
|
||||||
static Log4net()
|
static Log4net()
|
||||||
{
|
{
|
||||||
string log4netConfigPath = @"../Config/log4net.config";
|
string log4netConfigPath = Log4netConfigPath;
|
||||||
|
|
||||||
if (File.Exists(log4netConfigPath) == true)
|
if (File.Exists(log4netConfigPath) == true)
|
||||||
{
|
{
|
||||||
|
|||||||
34
Projects/SystemX.Core/SystemX.Core/Model/Auth/LoginModel.cs
Normal file
34
Projects/SystemX.Core/SystemX.Core/Model/Auth/LoginModel.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using log4net.Core;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SystemX.Core.Model.Auth
|
||||||
|
{
|
||||||
|
//로그인 요청 모델
|
||||||
|
public class LoginModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string? UserID { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string? Password { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
//로그인 응답 모델
|
||||||
|
public class LoginResponseModel
|
||||||
|
{
|
||||||
|
public string? UserID { get; set; }
|
||||||
|
public UserRole Role { get; set; }
|
||||||
|
public string? RoleName { get; set; }
|
||||||
|
|
||||||
|
public string? AccessToken { get; set; }
|
||||||
|
public long AccessTokenExpired { get; set; }
|
||||||
|
public string? RefreshToken { get; set; }
|
||||||
|
|
||||||
|
public ERROR_CODE? EC { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
23
Projects/SystemX.Core/SystemX.Core/Model/Auth/LogoutModel.cs
Normal file
23
Projects/SystemX.Core/SystemX.Core/Model/Auth/LogoutModel.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using log4net.Core;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SystemX.Core.Model.Auth
|
||||||
|
{
|
||||||
|
public class LogoutModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string? UserID { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LogoutResponseModel
|
||||||
|
{
|
||||||
|
public string? UserID { get; set; }
|
||||||
|
|
||||||
|
public ERROR_CODE? EC { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
using log4net.Core;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SystemX.Core.Model.Auth
|
||||||
|
{
|
||||||
|
//유저 등록 모델
|
||||||
|
public class RegisterModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string UserID { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string Password { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string PasswordConfirm { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public UserRole Role { get; set; } = UserRole.User;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RegisterResponseModel
|
||||||
|
{
|
||||||
|
public string? UserID { get; set; }
|
||||||
|
public UserRole Role { get; set; }
|
||||||
|
public string? RoleName { get; set; }
|
||||||
|
|
||||||
|
public ERROR_CODE? EC { get; set; } = ERROR_CODE.EC_USER_REGISTER_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
14
Projects/SystemX.Core/SystemX.Core/Model/Auth/UserModel.cs
Normal file
14
Projects/SystemX.Core/SystemX.Core/Model/Auth/UserModel.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SystemX.Core.Model.Auth
|
||||||
|
{
|
||||||
|
public class UserModel
|
||||||
|
{
|
||||||
|
//public TUser? TUser { get; set; }
|
||||||
|
//public TRole? TRole { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,7 +4,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace VPKI.Library.Enums
|
namespace SystemX.Core.Model.Auth
|
||||||
{
|
{
|
||||||
//User 권한
|
//User 권한
|
||||||
public enum UserRole : byte
|
public enum UserRole : byte
|
||||||
@ -4,7 +4,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace VPKI.Library.Enums
|
namespace SystemX.Core.Model.Auth
|
||||||
{
|
{
|
||||||
public enum UserState : byte
|
public enum UserState : byte
|
||||||
{
|
{
|
||||||
@ -9,18 +9,26 @@
|
|||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
<WarningLevel>9999</WarningLevel>
|
<WarningLevel>9999</WarningLevel>
|
||||||
|
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
<WarningLevel>9999</WarningLevel>
|
<WarningLevel>9999</WarningLevel>
|
||||||
|
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CsvHelper" Version="33.0.1" />
|
<PackageReference Include="CsvHelper" Version="33.0.1" />
|
||||||
<PackageReference Include="log4net" Version="3.0.4" />
|
<PackageReference Include="log4net" Version="3.0.4" />
|
||||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.6">
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.15" />
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.15" />
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.6" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.6">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,80 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<Name>SystemX.DB.AccountDB</Name>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectVersion>4.1</ProjectVersion>
|
||||||
|
<ProjectGuid>{b44c85fa-bd31-419f-8481-477e166a5753}</ProjectGuid>
|
||||||
|
<DSP>Microsoft.Data.Tools.Schema.Sql.Sql160DatabaseSchemaProvider</DSP>
|
||||||
|
<OutputType>Database</OutputType>
|
||||||
|
<RootPath>
|
||||||
|
</RootPath>
|
||||||
|
<RootNamespace>SystemX.DB.AccountDB</RootNamespace>
|
||||||
|
<AssemblyName>SystemX.DB.AccountDB</AssemblyName>
|
||||||
|
<ModelCollation>1042,CI</ModelCollation>
|
||||||
|
<DefaultFileStructure>BySchemaAndSchemaType</DefaultFileStructure>
|
||||||
|
<DeployToDatabase>True</DeployToDatabase>
|
||||||
|
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||||
|
<TargetLanguage>CS</TargetLanguage>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<SqlServerVerification>False</SqlServerVerification>
|
||||||
|
<IncludeCompositeObjects>True</IncludeCompositeObjects>
|
||||||
|
<TargetDatabaseSet>True</TargetDatabaseSet>
|
||||||
|
<GenerateCreateScript>True</GenerateCreateScript>
|
||||||
|
<DefaultCollation>Korean_Wansung_CI_AS</DefaultCollation>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<BuildScriptName>$(MSBuildProjectName).sql</BuildScriptName>
|
||||||
|
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<DefineDebug>false</DefineDebug>
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<BuildScriptName>$(MSBuildProjectName).sql</BuildScriptName>
|
||||||
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<DefineDebug>true</DefineDebug>
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">11.0</VisualStudioVersion>
|
||||||
|
<!-- Default to the v11.0 targets path if the targets file for the current VS version is not found -->
|
||||||
|
<SSDTExists Condition="Exists('$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets')">True</SSDTExists>
|
||||||
|
<VisualStudioVersion Condition="'$(SSDTExists)' == ''">11.0</VisualStudioVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Condition="'$(SQLDBExtensionsRefPath)' != ''" Project="$(SQLDBExtensionsRefPath)\Microsoft.Data.Tools.Schema.SqlTasks.targets" />
|
||||||
|
<Import Condition="'$(SQLDBExtensionsRefPath)' == ''" Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets" />
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Properties" />
|
||||||
|
<Folder Include="dbo" />
|
||||||
|
<Folder Include="dbo\Functions" />
|
||||||
|
<Folder Include="dbo\Scripts" />
|
||||||
|
<Folder Include="dbo\StoredProcedures" />
|
||||||
|
<Folder Include="dbo\Tables" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Build Include="dbo\Tables\tUser.sql" />
|
||||||
|
<Build Include="dbo\Tables\tRole.sql" />
|
||||||
|
<Build Include="dbo\Tables\tRefreshToken.sql" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PostDeploy Include="dbo\Scripts\scriptAfterBuild.sql" />
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<PostBuildEvent>xcopy /y $(ProjectDir)$(OutputPath)$(TargetName)_Create.sql $(SolutionDir)DBPatch\sqlScripts\
|
||||||
|
|
||||||
|
xcopy /y $(ProjectDir)$(OutputPath)$(TargetName).dacpac $(SolutionDir)DBPatch\sqlScripts\dacpac\</PostBuildEvent>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
배포 후 스크립트 템플릿
|
||||||
|
--------------------------------------------------------------------------------------
|
||||||
|
이 파일에는 빌드 스크립트에 추가될 SQL 문이 있습니다.
|
||||||
|
SQLCMD 구문을 사용하여 파일을 배포 후 스크립트에 포함합니다.
|
||||||
|
예: :r .\myfile.sql
|
||||||
|
SQLCMD 구문을 사용하여 배포 후 스크립트의 변수를 참조합니다.
|
||||||
|
예: :setvar TableName MyTable
|
||||||
|
SELECT * FROM [$(TableName)]
|
||||||
|
--------------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM tUser WHERE cUserID = 'Alis')
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO tUser (cUserID, cAuid, cPasswordHashed, cState, cCreateDateTime, cLastLoginDateTime)
|
||||||
|
VALUES ('Alis', 'SuperUserAlis' ,'oKLQCdunc2kT5aAVfK+POKwd8R3p8OZvs/NATwpg4gM=' ,1 ,GETDATE(), GETDATE());
|
||||||
|
|
||||||
|
INSERT INTO tRole(cAuid, cRoleID, cRoleName)
|
||||||
|
VALUES ('SuperUserAlis','20','SuperUser');
|
||||||
|
END
|
||||||
|
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM tUser WHERE cUserID = 'SystemX')
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO tUser (cUserID, cAuid, cPasswordHashed, cState, cCreateDateTime, cLastLoginDateTime)
|
||||||
|
VALUES ('SystemX', 'SuperUserSystemX' ,'S2irOEf+2n1sYsH7y+6/o16rc1HtXnj03a3qXfZLgBU=' ,1 ,GETDATE(), GETDATE());
|
||||||
|
|
||||||
|
INSERT INTO tRole(cAuid, cRoleID, cRoleName)
|
||||||
|
VALUES ('SuperUserSystemX','20','SuperUser');
|
||||||
|
END
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
CREATE TABLE [dbo].[tRefreshToken]
|
||||||
|
(
|
||||||
|
[cAuid] NVARCHAR(250) NOT NULL PRIMARY KEY,
|
||||||
|
[cRefreshToken] NVARCHAR(1000) NOT NULL
|
||||||
|
)
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
CREATE TABLE [dbo].[tRole]
|
||||||
|
(
|
||||||
|
[cAuid] NVARCHAR(250) NOT NULL PRIMARY KEY,
|
||||||
|
[cRoleID] TINYINT NOT NULL,
|
||||||
|
[cRoleName] NVARCHAR(20) NOT NULL
|
||||||
|
)
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
CREATE TABLE [dbo].[tUser]
|
||||||
|
(
|
||||||
|
[cUserID] NVARCHAR(50) NOT NULL,
|
||||||
|
[cAuid] NVARCHAR(250) NOT NULL ,
|
||||||
|
[cPasswordHashed] NVARCHAR(250) NOT NULL,
|
||||||
|
[cState] tinyint NOT NULL,
|
||||||
|
[cCreateDateTime] DATETIME2 NOT NULL,
|
||||||
|
[cLastLoginDateTime] DATETIME2 NULL,
|
||||||
|
PRIMARY KEY ([cUserID])
|
||||||
|
)
|
||||||
5
Projects/Tools/Tools_Scaffold_AccountDB.bat
Normal file
5
Projects/Tools/Tools_Scaffold_AccountDB.bat
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
::AccountDB
|
||||||
|
cd ../SystemX.Core/SystemX.Core
|
||||||
|
|
||||||
|
::WebApi
|
||||||
|
dotnet ef dbcontext scaffold "server=127.0.0.1; user id=SystemX; password=X; database=AccountDB; TrustServerCertificate=true;" Microsoft.EntityFrameworkCore.SqlServer --namespace SystemX.Core.DBContext --context-dir DBContext\AccountDB\Context --output-dir DBContext\AccountDB\Tables -f
|
||||||
@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
@ -6,8 +6,32 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.18" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||||
</ItemGroup>
|
</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>
|
</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);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
|
//singleton
|
||||||
|
builder.Services.AddSingleton<ConfigService<WebApiConfig>>();
|
||||||
|
builder.Services.AddScoped<AuthService>();
|
||||||
|
|
||||||
|
//scoped
|
||||||
|
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
builder.Services.AddSwaggerGen();
|
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();
|
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.
|
// Configure the HTTP request pipeline.
|
||||||
if (app.Environment.IsDevelopment())
|
if (app.Environment.IsDevelopment())
|
||||||
{
|
{
|
||||||
|
Log4net.WriteLine($"IsDevelopment:{app.Environment.IsDevelopment()}");
|
||||||
|
Log4net.WriteLine($"Swagger Url: {serverUrl}/swagger");
|
||||||
app.UseSwagger();
|
app.UseSwagger();
|
||||||
app.UseSwaggerUI();
|
app.UseSwaggerUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.UseAuthentication();
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
|
|
||||||
|
if (isIIS == true)
|
||||||
|
{
|
||||||
app.Run();
|
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
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AuthApi", "AuthApi\AuthApi.csproj", "{321DD194-9455-48F7-A0BE-EF6E95881714}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AuthApi", "AuthApi\AuthApi.csproj", "{321DD194-9455-48F7-A0BE-EF6E95881714}"
|
||||||
EndProject
|
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
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
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}.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.ActiveCfg = Release|Any CPU
|
||||||
{321DD194-9455-48F7-A0BE-EF6E95881714}.Release|Any CPU.Build.0 = 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
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
Reference in New Issue
Block a user