마이그레이션 및 보안 수정
TaxBaik CI/CD / build-and-deploy (push) Failing after 15s

- MigrationRunner: 이미 존재하는 테이블에 대한 "relation already exists" 오류 처리
- V002, V003 마이그레이션: ON CONFLICT DO NOTHING으로 멱등성 보장
- Web, Admin Program.cs: app.UseAntiforgery() 미들웨어 추가 (anti-forgery 토큰 검증)

변경사항:
- 마이그레이션 재실행 시에도 안전하게 처리
- 폼 제출 시 CSRF 공격 방지
- 관리자 로그인 페이지 405 에러 해결

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-06-26 16:46:36 +09:00
parent 701a841279
commit e7e01d0cd8
5 changed files with 21 additions and 4 deletions
+1
View File
@@ -44,6 +44,7 @@ app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseAntiforgery();
app.MapRazorComponents<TaxBaik.Admin.Components.App>()
.AddInteractiveServerRenderMode();
@@ -122,6 +122,17 @@ public class MigrationRunner
Console.WriteLine($"✓ Migration {migration.Version} executed");
}
catch (Npgsql.PostgresException pgEx) when (pgEx.SqlState == "42P07") // relation already exists
{
// Already executed previously; mark as done
Console.WriteLine($" Migration {migration.Version} already applied");
using var insertCmd = conn.CreateCommand();
insertCmd.CommandText =
"INSERT INTO schema_migrations (version, description) VALUES (@version, @description) ON CONFLICT (version) DO NOTHING;";
insertCmd.Parameters.AddWithValue("@version", migration.Version);
insertCmd.Parameters.AddWithValue("@description", migration.Description);
await insertCmd.ExecuteNonQueryAsync();
}
catch (Exception ex)
{
Console.WriteLine($"✗ Migration {migration.Version} failed: {ex.Message}");
+1
View File
@@ -29,6 +29,7 @@ app.UsePathBase("/taxbaik");
app.UseResponseCompression();
app.UseStaticFiles();
app.UseRouting();
app.UseAntiforgery();
if (!app.Environment.IsDevelopment())
{
+4 -2
View File
@@ -5,11 +5,13 @@ INSERT INTO categories (name, slug, sort_order) VALUES
('부동산 세금', 'real-estate-tax', 2),
('종합소득세', 'income-tax', 3),
('부가가치세', 'vat', 4),
('가족자산·증여', 'family-asset', 5);
('가족자산·증여', 'family-asset', 5)
ON CONFLICT (slug) DO NOTHING;
INSERT INTO site_settings (key, value) VALUES
('site.title', '백원숙 세무회계 | 사업자·부동산·증여 세무 상담'),
('site.description', '사업자 기장, 부동산 양도세·증여세, 종합소득세 전문 상담. 온라인 맞춤 상담 제공.'),
('kakao.channel.url', ''),
('phone.main', ''),
('consultation.fee.text','상담료 7만~20만 원, 계약 체결 시 일부 차감');
('consultation.fee.text','상담료 7만~20만 원, 계약 체결 시 일부 차감')
ON CONFLICT (key) DO NOTHING;
@@ -1,7 +1,8 @@
-- 초기 관리자 계정 (비밀번호: admin123)
-- bcrypt hash: $2a$11$N9qo8uLOickgx2ZMRZoMye (실제 환경에서는 강력한 암호 사용)
INSERT INTO admin_users (username, password_hash, created_at)
VALUES ('admin', '$2a$11$N9qo8uLOickgx2ZMRZoMye6IjfQTp5emXyqhT3jrDZWCqYIxJkAOq', NOW());
VALUES ('admin', '$2a$11$N9qo8uLOickgx2ZMRZoMye6IjfQTp5emXyqhT3jrDZWCqYIxJkAOq', NOW())
ON CONFLICT (username) DO NOTHING;
-- 초기 블로그 포스트 5개
INSERT INTO blog_posts (title, content, slug, category_id, tags, author_id, published_at, is_published, seo_title, seo_description, created_at, updated_at)
@@ -75,4 +76,5 @@ VALUES
'증여세를 절감하는 전략적인 증여 방법을 소개합니다.',
NOW(),
NOW()
);
)
ON CONFLICT (slug) DO NOTHING;