1
0
forked from baron/baron-sso

audit 로그 개선. kratos 코드발급 링크로 전송까지 진행 완료 #104

This commit is contained in:
Lectom C Han
2026-01-29 01:20:19 +09:00
parent ff17259117
commit b88de7ec91
46 changed files with 2843 additions and 585 deletions

View File

@@ -29,7 +29,6 @@ class AuditService {
'event_type': eventType,
'status': status,
'details': details,
'timestamp': DateTime.now().toIso8601String(),
}),
);

View File

@@ -1,6 +1,7 @@
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'http_client.dart';
class AuthProxyService {
static String _envOrDefault(String key, String fallback) {
@@ -22,6 +23,24 @@ class AuthProxyService {
}
}
static Future<Map<String, dynamic>> checkCookieSession() async {
final url = Uri.parse('$_baseUrl/api/v1/user/me');
final client = createHttpClient(withCredentials: true);
try {
final response = await client.get(
url,
headers: {'Content-Type': 'application/json'},
);
if (response.statusCode == 200) {
return jsonDecode(response.body);
}
throw Exception('Failed to load profile: ${response.body}');
} finally {
client.close();
}
}
static Future<Map<String, dynamic>> initEnchantedLink(String loginId, {String? method}) async {
final url = Uri.parse('$_baseUrl/api/v1/auth/enchanted-link/init');
final userfrontUrl = _envOrDefault('USERFRONT_URL', 'http://sso.hmac.kr');
@@ -60,9 +79,11 @@ class AuthProxyService {
if (response.statusCode == 200) {
return jsonDecode(response.body);
} else {
throw Exception('Polling failed: ${response.body}');
}
if (response.statusCode == 400) {
return jsonDecode(response.body);
}
throw Exception('Polling failed: ${response.body}');
}
static Future<Map<String, dynamic>> verifyMagicLink(String token) async {
@@ -83,6 +104,25 @@ class AuthProxyService {
}
}
static Future<Map<String, dynamic>> verifyLoginCode(String loginId, String code) async {
final url = Uri.parse('$_baseUrl/api/v1/auth/login/code/verify');
final response = await http.post(
url,
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
'loginId': loginId,
'code': code,
}),
);
if (response.statusCode == 200) {
return jsonDecode(response.body);
} else {
throw Exception('Verification failed: ${response.body}');
}
}
static Future<Map<String, dynamic>> loginWithPassword(String loginId, String password) async {
final url = Uri.parse('$_baseUrl/api/v1/auth/password/login');
@@ -205,9 +245,11 @@ class AuthProxyService {
if (response.statusCode == 200) {
return jsonDecode(response.body);
} else {
throw Exception('QR Polling failed: ${response.body}');
}
if (response.statusCode == 400) {
return jsonDecode(response.body);
}
throw Exception('QR Polling failed: ${response.body}');
}
static Future<void> approveQrLogin(String pendingRef, String token) async {

View File

@@ -0,0 +1,32 @@
import 'auth_token_store_stub.dart'
if (dart.library.html) 'auth_token_store_web.dart';
class AuthTokenStore {
static String? getToken() => authTokenStore.getToken();
static String? getProvider() => authTokenStore.getProvider();
static bool usesCookie() => authTokenStore.usesCookie();
static void setToken(String token, {String? provider}) {
authTokenStore.setToken(token, provider: provider);
}
static void setCookieMode({String? provider}) {
authTokenStore.setCookieMode(provider: provider);
}
static String? getPendingProvider() => authTokenStore.getPendingProvider();
static void setPendingProvider(String? provider) {
authTokenStore.setPendingProvider(provider);
}
static void clearPendingProvider() {
authTokenStore.setPendingProvider(null);
}
static void clear() {
authTokenStore.clear();
}
}

View File

@@ -0,0 +1,41 @@
class AuthTokenStore {
String? _token;
String? _provider;
bool _cookieMode = false;
String? _pendingProvider;
String? getToken() => _token;
String? getProvider() => _provider;
bool usesCookie() => _cookieMode;
void setToken(String token, {String? provider}) {
_token = token;
_cookieMode = false;
_provider = provider;
}
void setCookieMode({String? provider}) {
_cookieMode = true;
_token = null;
if (provider != null) {
_provider = provider;
}
}
String? getPendingProvider() => _pendingProvider;
void setPendingProvider(String? provider) {
_pendingProvider = provider;
}
void clear() {
_token = null;
_provider = null;
_cookieMode = false;
_pendingProvider = null;
}
}
final authTokenStore = AuthTokenStore();

View File

@@ -0,0 +1,49 @@
import 'dart:html' as html;
class AuthTokenStore {
static const _tokenKey = 'baron_auth_token';
static const _providerKey = 'baron_auth_provider';
static const _cookieModeKey = 'baron_auth_cookie_mode';
static const _pendingProviderKey = 'baron_auth_pending_provider';
String? getToken() => html.window.localStorage[_tokenKey];
String? getProvider() => html.window.localStorage[_providerKey];
bool usesCookie() => html.window.localStorage[_cookieModeKey] == '1';
void setToken(String token, {String? provider}) {
html.window.localStorage[_tokenKey] = token;
html.window.localStorage.remove(_cookieModeKey);
if (provider != null) {
html.window.localStorage[_providerKey] = provider;
}
}
void setCookieMode({String? provider}) {
html.window.localStorage[_cookieModeKey] = '1';
html.window.localStorage.remove(_tokenKey);
if (provider != null) {
html.window.localStorage[_providerKey] = provider;
}
}
String? getPendingProvider() => html.window.localStorage[_pendingProviderKey];
void setPendingProvider(String? provider) {
if (provider == null || provider.isEmpty) {
html.window.localStorage.remove(_pendingProviderKey);
return;
}
html.window.localStorage[_pendingProviderKey] = provider;
}
void clear() {
html.window.localStorage.remove(_tokenKey);
html.window.localStorage.remove(_providerKey);
html.window.localStorage.remove(_cookieModeKey);
html.window.localStorage.remove(_pendingProviderKey);
}
}
final authTokenStore = AuthTokenStore();

View File

@@ -0,0 +1,7 @@
import 'package:http/http.dart' as http;
import 'http_client_stub.dart'
if (dart.library.html) 'http_client_web.dart';
http.Client createHttpClient({bool withCredentials = false}) {
return httpClientFactory.create(withCredentials: withCredentials);
}

View File

@@ -0,0 +1,9 @@
import 'package:http/http.dart' as http;
class HttpClientFactory {
http.Client create({bool withCredentials = false}) {
return http.Client();
}
}
final httpClientFactory = HttpClientFactory();

View File

@@ -0,0 +1,12 @@
import 'package:http/browser_client.dart';
import 'package:http/http.dart' as http;
class HttpClientFactory {
http.Client create({bool withCredentials = false}) {
final client = BrowserClient();
client.withCredentials = withCredentials;
return client;
}
}
final httpClientFactory = HttpClientFactory();