[성현모] AuthApi 분리

This commit is contained in:
SHM
2025-07-15 10:16:26 +09:00
parent 20f1e7e7e5
commit 7a12be392a
52 changed files with 1931 additions and 60 deletions

View 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"
}
]
}

View 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.

View File

@ -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)
{ {

View File

@ -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)
{ {

View File

@ -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();

View 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

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View 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; }
}
}

View File

@ -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);
}

View File

@ -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!;
}

View File

@ -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!;
}

View File

@ -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; }
}

View 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
}
}

View File

@ -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)
{ {

View 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; }
}
}

View 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; }
}
}

View File

@ -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;
}
}

View 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; }
}
}

View File

@ -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

View File

@ -4,9 +4,9 @@ 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
{ {
Inactive = 0, Inactive = 0,
Active = 1, Active = 1,

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -0,0 +1,5 @@
CREATE TABLE [dbo].[tRefreshToken]
(
[cAuid] NVARCHAR(250) NOT NULL PRIMARY KEY,
[cRefreshToken] NVARCHAR(1000) NOT NULL
)

View File

@ -0,0 +1,6 @@
CREATE TABLE [dbo].[tRole]
(
[cAuid] NVARCHAR(250) NOT NULL PRIMARY KEY,
[cRoleID] TINYINT NOT NULL,
[cRoleName] NVARCHAR(20) NOT NULL
)

View File

@ -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])
)

View 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

View File

@ -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>

View 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);
}
}
}

View 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;
}
}
}

View File

@ -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();
}
}
}

View File

@ -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();
app.Run(); if (isIIS == true)
{
app.Run();
}
else
{
Log4net.WriteLine($"Operation Url: {serverUrl}");
app.Run($"{serverUrl}");
}

View 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;
}
}
}

View File

@ -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; }
}
}

View File

@ -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);
}

View File

@ -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!;
}

View File

@ -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!;
}

View File

@ -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; }
}

View File

@ -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>

View 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; }
}
}

View 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>

View File

@ -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