main #21
|
@ -8,17 +8,17 @@ namespace Front;
|
|||
public partial class App : ComponentBase
|
||||
{
|
||||
[Inject] private APIService API { get; set; } = default!;
|
||||
[Inject] private CookieService Cookie { get; set; } = default!;
|
||||
[Inject] private StorageService StorageService { get; set; } = default!;
|
||||
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
var cookie = await Cookie.GetCookieAsync("Web_AM_Connect_Key");
|
||||
var headerValue = await StorageService.GetItemAsync("Web_AM_Connect_Key");
|
||||
|
||||
// 값 없으면 API 호출
|
||||
if (string.IsNullOrEmpty(cookie))
|
||||
if (string.IsNullOrEmpty(headerValue))
|
||||
{
|
||||
var response = await API.GetJsonAsync<APIHeader, AppHeader>(
|
||||
"/api/v1/in/app",
|
||||
|
@ -30,7 +30,7 @@ public partial class App : ComponentBase
|
|||
});
|
||||
if (!string.IsNullOrEmpty(response.data.header))
|
||||
{
|
||||
await Cookie.SetCookieAsync("Web_AM_Connect_Key", response.data.header);
|
||||
await StorageService.SetItemAsync("Web_AM_Connect_Key", response.data.header);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,9 @@ var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
|||
builder.RootComponents.Add<App>("#app");
|
||||
builder.RootComponents.Add<HeadOutlet>("head::after");
|
||||
|
||||
// 설정 파일 로드
|
||||
// builder.Configuration.AddJsonFile("appsettings.json", optional: false);
|
||||
builder.Configuration.AddJsonFile($"appsettings.{builder.HostEnvironment.Environment}.json", optional: true);
|
||||
|
||||
builder.Services.AddScoped(sp => //new HttpClient
|
||||
{
|
||||
|
@ -30,7 +33,8 @@ builder.Services.AddScoped(sp => //new HttpClient
|
|||
|
||||
// SCOPED 으로 등록된 서비스는 DI 컨테이너에 등록된 서비스의 인스턴스를 사용합니다.
|
||||
builder.Services.AddScoped<APIService>();
|
||||
builder.Services.AddScoped<CookieService>();
|
||||
builder.Services.AddScoped<SecureService>();
|
||||
builder.Services.AddScoped<StorageService>();
|
||||
// builder.Services.AddRazorPages();
|
||||
// builder.Services.AddServerSideBlazor();
|
||||
builder.Services.AddScoped<LoadingService>();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Routing;
|
||||
|
||||
using Front.Program.Views.Project;
|
||||
using Front.Program.Services;
|
||||
|
||||
|
@ -13,6 +14,9 @@ public partial class MainLayout : LayoutComponentBase, IDisposable
|
|||
[Inject]
|
||||
LoadingService LoadingService { get; set; } = default!;
|
||||
|
||||
[Inject]
|
||||
StorageService StorageService { get; set; } = default!;
|
||||
|
||||
// 경로의 시작 부분
|
||||
// protected bool isHidePrjTop => Navigation.ToBaseRelativePath(Navigation.Uri).StartsWith("auth", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
|
@ -23,11 +27,43 @@ public partial class MainLayout : LayoutComponentBase, IDisposable
|
|||
{
|
||||
LoadingService.OnChange += StateHasChanged;
|
||||
Navigation.LocationChanged += HandleLocationChanged;
|
||||
HandleLocationChanged(this, new LocationChangedEventArgs(Navigation.Uri, false));
|
||||
}
|
||||
|
||||
private void HandleLocationChanged(object? sender, LocationChangedEventArgs e)
|
||||
private async void HandleLocationChanged(object? sender, LocationChangedEventArgs e)
|
||||
{
|
||||
LoadingService.HideNavigationLoading();
|
||||
|
||||
var uri = Navigation.ToAbsoluteUri(Navigation.Uri);
|
||||
Console.WriteLine($"리다이렉트된 URI: {uri}");
|
||||
|
||||
if (uri.Query.Contains("auth="))
|
||||
{
|
||||
var query = uri.Query.TrimStart('?');
|
||||
var parameters = query.Split('&')
|
||||
.Select(p => p.Split('='))
|
||||
.Where(p => p.Length == 2)
|
||||
.ToDictionary(p => p[0], p => p[1]);
|
||||
|
||||
if (parameters.TryGetValue("auth", out var auth))
|
||||
{
|
||||
Console.WriteLine($"auth 파라미터 값: {auth}");
|
||||
if (auth == "true")
|
||||
{
|
||||
await StorageService.SetItemAsync("IsLogin", "true");
|
||||
Console.WriteLine("로그인 상태를 true로 설정했습니다.");
|
||||
}
|
||||
else
|
||||
{
|
||||
await StorageService.RemoveItemAsync("IsLogin");
|
||||
Console.WriteLine("로그인 상태를 제거했습니다.");
|
||||
}
|
||||
|
||||
// 파라미터를 제거하고 리다이렉트
|
||||
var baseUri = uri.GetLeftPart(UriPartial.Path);
|
||||
Navigation.NavigateTo(baseUri, forceLoad: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
|
@ -29,3 +29,14 @@ public class APIService
|
|||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
dynamic 타입을 사용하면:
|
||||
타입 안전성이 떨어집니다
|
||||
컴파일 타임에 오류를 잡을 수 없습니다
|
||||
런타임에 예상치 못한 오류가 발생할 수 있습니다
|
||||
현재 Register.razor.cs에서 JsonElement를 사용하는 방식이 더 안전할 수 있습니다. 왜냐하면:
|
||||
JSON 응답의 구조를 명시적으로 확인할 수 있습니다 (TryGetProperty 사용)
|
||||
각 속성의 타입을 명확하게 처리할 수 있습니다
|
||||
예상치 못한 데이터 구조에 대해 더 안전하게 대응할 수 있습니다
|
||||
*/
|
|
@ -1,29 +0,0 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
namespace Front.Program.Services;
|
||||
|
||||
public class CookieService
|
||||
{
|
||||
private readonly IJSRuntime _js;
|
||||
|
||||
public CookieService(IJSRuntime js)
|
||||
{
|
||||
_js = js;
|
||||
}
|
||||
|
||||
public async Task SetCookieAsync(string key, string value)
|
||||
{
|
||||
await _js.InvokeVoidAsync("setCookie", key, value, 1);
|
||||
}
|
||||
|
||||
public async Task<string?> GetCookieAsync(string key)
|
||||
{
|
||||
return await _js.InvokeAsync<string>("getCookie", key);
|
||||
}
|
||||
|
||||
public async Task DeleteCookieAsync(string key)
|
||||
{
|
||||
await _js.InvokeVoidAsync("deleteCookie", key);
|
||||
}
|
||||
}
|
120
Program/Services/SecureService.cs
Normal file
120
Program/Services/SecureService.cs
Normal file
|
@ -0,0 +1,120 @@
|
|||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Microsoft.JSInterop;
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
|
||||
namespace Front.Program.Services;
|
||||
|
||||
public class SecureService
|
||||
{
|
||||
private readonly ILogger<SecureService> _logger;
|
||||
private readonly IJSRuntime _jsRuntime;
|
||||
private readonly IWebAssemblyHostEnvironment _environment;
|
||||
private string? _key;
|
||||
private string? _iv;
|
||||
private Task? _initializationTask;
|
||||
|
||||
public SecureService(
|
||||
ILogger<SecureService> logger,
|
||||
IJSRuntime jsRuntime,
|
||||
IWebAssemblyHostEnvironment environment)
|
||||
{
|
||||
_logger = logger;
|
||||
_jsRuntime = jsRuntime;
|
||||
_environment = environment;
|
||||
_initializationTask = InitializeAsync();
|
||||
}
|
||||
|
||||
private async Task InitializeAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var configFile = $"appsettings.{_environment.Environment}.json";
|
||||
_logger.LogInformation($"설정 파일 로드: {configFile}");
|
||||
|
||||
var config = await _jsRuntime.InvokeAsync<JsonElement>("loadConfig", configFile);
|
||||
if (config.ValueKind == JsonValueKind.Null)
|
||||
{
|
||||
throw new InvalidOperationException($"설정 파일을 로드할 수 없습니다: {configFile}");
|
||||
}
|
||||
|
||||
var security = config.GetProperty("Security");
|
||||
_key = security.GetProperty("EncryptionKey").GetString()
|
||||
?? throw new ArgumentNullException("Security:EncryptionKey");
|
||||
_iv = security.GetProperty("EncryptionIV").GetString()
|
||||
?? throw new ArgumentNullException("Security:EncryptionIV");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"설정 로드 중 오류 발생: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task EnsureInitializedAsync()
|
||||
{
|
||||
if (_initializationTask != null)
|
||||
{
|
||||
await _initializationTask;
|
||||
_initializationTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] GetKeyBytes(string key)
|
||||
{
|
||||
using (var sha256 = SHA256.Create())
|
||||
{
|
||||
return sha256.ComputeHash(Encoding.UTF8.GetBytes(key));
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] GetIVBytes(string iv)
|
||||
{
|
||||
using (var sha256 = SHA256.Create())
|
||||
{
|
||||
var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(iv));
|
||||
return hash.Take(16).ToArray(); // IV는 16바이트만 필요
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string> EncryptAsync(string plainText)
|
||||
{
|
||||
await EnsureInitializedAsync();
|
||||
|
||||
if (_key == null || _iv == null)
|
||||
throw new InvalidOperationException("암호화 키가 초기화되지 않았습니다.");
|
||||
|
||||
try
|
||||
{
|
||||
return await _jsRuntime.InvokeAsync<string>("encryptText", plainText, _key, _iv);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"암호화 중 오류 발생: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string> DecryptAsync(string cipherText)
|
||||
{
|
||||
await EnsureInitializedAsync();
|
||||
|
||||
if (_key == null || _iv == null)
|
||||
throw new InvalidOperationException("암호화 키가 초기화되지 않았습니다.");
|
||||
|
||||
try
|
||||
{
|
||||
return await _jsRuntime.InvokeAsync<string>("decryptText", cipherText, _key, _iv);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"복호화 중 오류 발생: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// 동기 메서드는 비동기 메서드를 호출하도록 수정
|
||||
public string Encrypt(string plainText) => EncryptAsync(plainText).GetAwaiter().GetResult();
|
||||
public string Decrypt(string cipherText) => DecryptAsync(cipherText).GetAwaiter().GetResult();
|
||||
}
|
75
Program/Services/StorageService.cs
Normal file
75
Program/Services/StorageService.cs
Normal file
|
@ -0,0 +1,75 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
namespace Front.Program.Services;
|
||||
|
||||
public enum STORAGE_TYPE
|
||||
{
|
||||
Cookie,
|
||||
Local,
|
||||
Session
|
||||
}
|
||||
|
||||
public class StorageService
|
||||
{
|
||||
private readonly IJSRuntime _js;
|
||||
|
||||
public StorageService(IJSRuntime js)
|
||||
{
|
||||
_js = js;
|
||||
}
|
||||
|
||||
public async Task SetItemAsync(string key, string value, STORAGE_TYPE type = STORAGE_TYPE.Session, int expire_time = 1)
|
||||
{
|
||||
await (type switch
|
||||
{
|
||||
STORAGE_TYPE.Cookie => _js.InvokeVoidAsync("setCookie", key, value, expire_time),
|
||||
STORAGE_TYPE.Local => _js.InvokeVoidAsync("localStorage.setItem", key, value),
|
||||
STORAGE_TYPE.Session => _js.InvokeVoidAsync("sessionStorage.setItem", key, value),
|
||||
_ => throw new ArgumentException("Invalid storage type")
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<string?> GetItemAsync(string key, STORAGE_TYPE type = STORAGE_TYPE.Session)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
STORAGE_TYPE.Cookie => await _js.InvokeAsync<string>("getCookie", key),
|
||||
STORAGE_TYPE.Local => await _js.InvokeAsync<string>("localStorage.getItem", key),
|
||||
STORAGE_TYPE.Session => await _js.InvokeAsync<string>("sessionStorage.getItem", key),
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
public async Task RemoveItemAsync(string key, STORAGE_TYPE type = STORAGE_TYPE.Session)
|
||||
{
|
||||
await (type switch
|
||||
{
|
||||
STORAGE_TYPE.Cookie => _js.InvokeVoidAsync("deleteCookie", key),
|
||||
STORAGE_TYPE.Local => _js.InvokeVoidAsync("localStorage.removeItem", key),
|
||||
STORAGE_TYPE.Session => _js.InvokeVoidAsync("sessionStorage.removeItem", key),
|
||||
_ => throw new ArgumentException("Invalid storage type")
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* 스토리지 종류
|
||||
1. Cookie
|
||||
만료일 : 명시적으로 설정이 가능 (설정에 따라 그 값을 변경 가능)
|
||||
접근성 : 서버와 클라이언트 모두 접근이 가능함
|
||||
특징
|
||||
1. HTTP 요청마다 서버로 전송이 되며 도메인/경로 제한이 가능하다.
|
||||
2. HttpOnly나 secure 옵션으로 보안 설정이 가능하다.
|
||||
2. Local
|
||||
만료일 : 브라우저 데이터 삭제 전까지는 영구 보관 가능
|
||||
접근성 : 클라이언트 측에서 JS 를 통해서만 접근이 가능
|
||||
특징
|
||||
1. 도메인별로 분리된 저장소로 동기적인 동작이 된다.
|
||||
2. 문자열만 저장이 가능하다.
|
||||
3. Sesson
|
||||
만료일 : 브라우저의 탭/창 닫을 때 까지 보관 (닫게 되면 삭제)
|
||||
접근성 : 클라이언트 측에서 JS 를 통해서만 접근이 가능
|
||||
특징
|
||||
1. 탭/창 별로 불리된 저장소며 동기적인 동작이 가능하다.
|
||||
2. 문자열만 저장이 가능하다.
|
||||
*/
|
|
@ -16,6 +16,7 @@ public partial class Register : ComponentBase
|
|||
[Inject] private HttpClient Http { get; set; } = default!;
|
||||
[Inject] private IConfiguration Configuration { get; set; } = default!;
|
||||
[Inject] private LoadingService LoadingService { get; set; } = default!;
|
||||
[Inject] private StorageService CookieService { get; set; } = default!;
|
||||
|
||||
private ElementReference dateInputRef;
|
||||
|
||||
|
@ -39,8 +40,7 @@ public partial class Register : ComponentBase
|
|||
objRef = DotNetObjectReference.Create(this);
|
||||
try
|
||||
{
|
||||
// 쿠키에서 토큰 가져오기
|
||||
var token = await JS.InvokeAsync<string>("eval", "document.cookie.split('; ').find(row => row.startsWith('Web_AM_Connect_Key='))?.split('=')[1]");
|
||||
var token = await CookieService.GetItemAsync("Web_AM_Connect_Key");
|
||||
if (string.IsNullOrEmpty(token))
|
||||
{
|
||||
await JS.InvokeVoidAsync("alert", "인증 정보가 없습니다.");
|
||||
|
@ -169,8 +169,7 @@ public partial class Register : ComponentBase
|
|||
try
|
||||
{
|
||||
LoadingService.ShowLoading();
|
||||
// 쿠키에서 토큰 가져오기
|
||||
var token = await JS.InvokeAsync<string>("eval", "document.cookie.split('; ').find(row => row.startsWith('Web_AM_Connect_Key='))?.split('=')[1] || ''");
|
||||
var token = await CookieService.GetItemAsync("Web_AM_Connect_Key");
|
||||
Console.WriteLine($"쿠키에서 가져온 토큰: '{token}'");
|
||||
|
||||
if (string.IsNullOrEmpty(token))
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<a class="text-text-title font-medium leading-normal hover:text-blue-600" href="/join" @onclick="() => isOpen = !isOpen">Join</a>
|
||||
<a class="text-text-title font-medium leading-normal hover:text-blue-600" href="/new" @onclick="() => isOpen = !isOpen">What's New</a>
|
||||
</div>
|
||||
@if (!isLoggedIn)
|
||||
@if (!isLogin)
|
||||
{
|
||||
<button class="flex min-w-[84px] max-w-[480px] cursor-pointer items-center justify-center overflow-hidden rounded-lg h-10 px-4 bg-second-normal hover:bg-second-dark text-white text-sm font-bold leading-normal tracking-[0.015em] mr-4"
|
||||
@onclick="OnClickLogin">
|
||||
|
@ -38,7 +38,7 @@
|
|||
<a class="block w-full gap-y-2 text-text-title font-medium leading-normal hover:text-blue-600" href="/about" @onclick="() => isOpen = !isOpen">About</a>
|
||||
<a class="block w-full gap-y-2 text-text-title font-medium leading-normal hover:text-blue-600" href="/join" @onclick="() => isOpen = !isOpen">Join</a>
|
||||
<a class="block w-full gap-y-2 text-text-title font-medium leading-normal hover:text-blue-600" href="/new" @onclick="() => isOpen = !isOpen">What's New</a>
|
||||
@if (!isLoggedIn)
|
||||
@if (!isLogin)
|
||||
{
|
||||
<button class="flex w-full cursor-pointer items-center justify-center rounded-lg h-10 px-4 bg-second-normal hover:bg-second-dark text-white text-sm font-bold leading-normal tracking-[0.015em]"
|
||||
@onclick="OnClickLogin">
|
||||
|
|
|
@ -1,24 +1,123 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using System;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using Front.Program.Services;
|
||||
|
||||
namespace Front.Program.Views.Project;
|
||||
|
||||
public partial class TopProjectNav : ComponentBase
|
||||
{
|
||||
[Inject]
|
||||
NavigationManager NavigationManager { get; set; } = default!;
|
||||
[Inject] NavigationManager NavigationManager { get; set; } = default!;
|
||||
[Inject] StorageService StorageService { get; set; } = default!;
|
||||
[Inject] SecureService SecureService { get; set; } = default!;
|
||||
|
||||
[Inject]
|
||||
IJSRuntime JS { get; set; } = default!;
|
||||
[Inject] IJSRuntime JS { get; set; } = default!;
|
||||
|
||||
[Inject] HttpClient Http { get; set; } = default!;
|
||||
string UserName { get; set; } = default!;
|
||||
|
||||
protected bool isOpen = false;
|
||||
protected bool isLoggedIn = false;
|
||||
bool isLogin = false;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
// 쿠키에서 로그인 상태 확인
|
||||
var isLoginCookie = await JS.InvokeAsync<string>("eval", "document.cookie.split('; ').find(row => row.startsWith('IsLogin='))?.split('=')[1]");
|
||||
isLoggedIn = isLoginCookie == "true";
|
||||
Console.WriteLine("TopNAV 확인");
|
||||
isLogin = isLogin = bool.TryParse(await StorageService.GetItemAsync("IsLogin"), out var result) && result;
|
||||
if (isLogin) return;
|
||||
try
|
||||
{
|
||||
|
||||
var encryptedName = await StorageService.GetItemAsync("USER");
|
||||
Console.WriteLine($"{encryptedName}");
|
||||
if (!string.IsNullOrEmpty(encryptedName))
|
||||
{
|
||||
try
|
||||
{
|
||||
UserName = await SecureService.DecryptAsync(encryptedName);
|
||||
Console.WriteLine($"세션 스토리지에서 가져온 사용자 이름: '{UserName}'");
|
||||
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"이름 복호화 중 오류 발생: {ex.Message}");
|
||||
await StorageService.RemoveItemAsync("USER");
|
||||
}
|
||||
}
|
||||
|
||||
// apiSender.js의 함수를 사용하여 연결 키 가져오기
|
||||
var headerValue = await StorageService.GetItemAsync("Web_AM_Connect_Key");
|
||||
Console.WriteLine($"세션 스토리지에서 가져온 헤더 값: '{headerValue}'");
|
||||
|
||||
if (string.IsNullOrEmpty(headerValue))
|
||||
{
|
||||
Console.WriteLine("연결 키가 없습니다");
|
||||
return;
|
||||
}
|
||||
|
||||
// apiSender.js의 함수를 사용하여 API 호출
|
||||
Console.WriteLine("세션 API 호출 시작");
|
||||
var response = await JS.InvokeAsync<JsonElement>("fetchWithHeaderAndReturnUrl",
|
||||
"/api/v1/in/user/auth/session",
|
||||
"GET",
|
||||
"Web_AM_Connect_Key",
|
||||
headerValue);
|
||||
|
||||
Console.WriteLine($"세션 API 응답 타입: {response.ValueKind}");
|
||||
Console.WriteLine($"세션 API 응답 내용: {response}");
|
||||
|
||||
if (response.ValueKind == JsonValueKind.Null || response.ValueKind == JsonValueKind.Undefined)
|
||||
{
|
||||
Console.WriteLine("응답이 null이거나 undefined입니다");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (response.TryGetProperty("status", out var statusElement))
|
||||
{
|
||||
Console.WriteLine($"status 요소 타입: {statusElement.ValueKind}");
|
||||
if (statusElement.TryGetProperty("code", out var codeElement))
|
||||
{
|
||||
var code = codeElement.GetString();
|
||||
Console.WriteLine($"응답 코드: {code}");
|
||||
|
||||
if (code == "000")
|
||||
{
|
||||
if (response.TryGetProperty("data", out var dataElement))
|
||||
{
|
||||
Console.WriteLine($"data 요소 타입: {dataElement.ValueKind}");
|
||||
if (dataElement.TryGetProperty("name", out var nameElement))
|
||||
{
|
||||
UserName = nameElement.GetString() ?? "이름 없음";
|
||||
isLogin = true;
|
||||
Console.WriteLine($"NM: {UserName}");
|
||||
var encryptedUserName = await SecureService.EncryptAsync(UserName);
|
||||
Console.WriteLine($"NM: {encryptedUserName}");
|
||||
await StorageService.SetItemAsync("USER", encryptedUserName);
|
||||
await StorageService.SetItemAsync("Web_AM_Connect_Key", headerValue);
|
||||
Console.WriteLine($"로그인된 사용자: {UserName}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Console.WriteLine("로그인되지 않은 상태");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"응답 처리 중 오류 발생: {ex.Message}");
|
||||
Console.WriteLine($"응답 처리 스택 트레이스: {ex.StackTrace}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"세션 확인 중 오류 발생: {ex.Message}");
|
||||
Console.WriteLine($"스택 트레이스: {ex.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnClickMenuDown()
|
||||
|
|
13
appsettings.json
Normal file
13
appsettings.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Security": {
|
||||
"EncryptionKey": "AcaMate2025SecureKeySeanForEncryption19940509",
|
||||
"EncryptionIV": "AcaMate2025IV9459"
|
||||
}
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
{
|
||||
"ApiBaseUrl": "https://devacamate.ipstein.myds.me/"
|
||||
"ApiBaseUrl": "https://devacamate.ipstein.myds.me/",
|
||||
"Security": {
|
||||
"EncryptionKey": "AcaMate2025SecureKeyForEncryptionSean1994",
|
||||
"EncryptionIV": "AcaMate2025IV9459"
|
||||
}
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
{
|
||||
"ApiBaseUrl": "https://acamate.ipstein.myds.me/"
|
||||
"ApiBaseUrl": "https://acamate.ipstein.myds.me/",
|
||||
"Security": {
|
||||
"EncryptionKey": "AcaMate2025SecureKeyForEncryptionSean1994",
|
||||
"EncryptionIV": "AcaMate2025IV9459"
|
||||
}
|
||||
}
|
|
@ -70,6 +70,7 @@
|
|||
const v = document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)');
|
||||
return v ? v.pop() : '';
|
||||
};
|
||||
|
||||
window.setCookie = function (name, value, days) {
|
||||
let expires = "";
|
||||
if (days) {
|
||||
|
|
|
@ -12,12 +12,85 @@ window.postWithHeader = function(url, method, headerKey, headerValue) {
|
|||
};
|
||||
|
||||
window.fetchWithHeaderAndReturnUrl = async function(url, method, headerKey, headerValue) {
|
||||
const response = await fetch(url, {
|
||||
method: method,
|
||||
headers: {
|
||||
[headerKey]: headerValue
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: method,
|
||||
headers: {
|
||||
[headerKey]: headerValue
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.error('API 호출 실패:', response.status, response.statusText);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
const data = await response.json();
|
||||
return data.url;
|
||||
|
||||
const data = await response.json();
|
||||
console.log('API 응답 데이터:', data);
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('API 호출 중 오류 발생:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
window.loadConfig = async function(configFile) {
|
||||
try {
|
||||
console.log('설정 파일 로드 시도:', configFile);
|
||||
const response = await fetch(configFile);
|
||||
if (!response.ok) {
|
||||
console.error('설정 파일 로드 실패:', response.status, response.statusText);
|
||||
return null;
|
||||
}
|
||||
const config = await response.json();
|
||||
console.log('설정 파일 로드 성공:', configFile);
|
||||
return config;
|
||||
} catch (error) {
|
||||
console.error('설정 파일 로드 중 오류 발생:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
window.encryptText = async function(text, key, iv) {
|
||||
try {
|
||||
// XOR 암호화 구현
|
||||
let result = '';
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
const charCode = text.charCodeAt(i) ^ key.charCodeAt(i % key.length);
|
||||
result += String.fromCharCode(charCode);
|
||||
}
|
||||
|
||||
// UTF-8로 인코딩 후 Base64로 변환
|
||||
const utf8Encoder = new TextEncoder();
|
||||
const bytes = utf8Encoder.encode(result);
|
||||
const base64 = btoa(String.fromCharCode.apply(null, bytes));
|
||||
return base64;
|
||||
} catch (error) {
|
||||
console.error('암호화 중 오류 발생:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
window.decryptText = async function(encryptedText, key, iv) {
|
||||
try {
|
||||
// Base64 디코딩 후 UTF-8 디코딩
|
||||
const binary = atob(encryptedText);
|
||||
const bytes = new Uint8Array(binary.length);
|
||||
for (let i = 0; i < binary.length; i++) {
|
||||
bytes[i] = binary.charCodeAt(i);
|
||||
}
|
||||
const utf8Decoder = new TextDecoder();
|
||||
const text = utf8Decoder.decode(bytes);
|
||||
|
||||
// XOR 복호화
|
||||
let result = '';
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
const charCode = text.charCodeAt(i) ^ key.charCodeAt(i % key.length);
|
||||
result += String.fromCharCode(charCode);
|
||||
}
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('복호화 중 오류 발생:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user