Compare commits

..

No commits in common. "8df11c3d8ca115dbc389fe5cb67f76d674e1d474" and "49d2e22524d64439439b2a5ce08b04a9f9e3f20c" have entirely different histories.

3 changed files with 125 additions and 66 deletions

View File

@ -11,6 +11,7 @@
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.10" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.10" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.8"/> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.8"/>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" /> <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.1.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="7.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="7.1.0" /> <PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="7.1.0" />

View File

@ -1,4 +1,3 @@
using AcaMate.V1.Models;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using AcaMate.V1.Services; using AcaMate.V1.Services;
@ -29,33 +28,38 @@ public class PushController : ControllerBase
[HttpPost("send")] [HttpPost("send")]
[CustomOperation("푸시전송", "저장된 양식으로, 사용자에게 푸시를 전송한다.", "푸시")] [CustomOperation("푸시전송", "저장된 양식으로, 사용자에게 푸시를 전송한다.", "푸시")]
// public async Task<IActionResult> SendPush(string deviceToken, string title, string body, int badge) public async Task<IActionResult> SendPush(string deviceToken, string title, string body, int badge)
public async Task<IActionResult> SendPush(string deviceToken, [FromBody] Payload payload)
{ {
var keysFilePath = "/src/private/appleKeys.json";
string p12Path = ""; // var keysFilePath = "private/appleKeys.json";
string p12PWPath = "private/appleKeys.json"; var uri = "";
string apnsTopic = "me.myds.ipstein.acamate.AcaMate"; var p12FilePath = "";
string uri = "";
if (_env.IsDevelopment()) if (_env.IsDevelopment())
{ {
uri = "https://api.sandbox.push.apple.com/"; // TEST
// p12Path = "/src/private/AM_Push_Sandbox.p12"; Console.WriteLine($"Current Directory: {Environment.CurrentDirectory}");
p12Path = "private/AM_Push_Sandbox.p12";
uri = "https://api.sandbox.push.apple.com";
p12FilePath = "/src/private/AM_Push_Sandbox.p12";
// p12FilePath = "private/AM_Push_Sandbox.p12";
} }
else else
{ {
uri = "https://api.push.apple.com/"; uri = "https://api.push.apple.com";
// p12Path = "/src/private/AM_Push.p12"; p12FilePath = "/src/private/AM_Push.p12";
p12Path = "private/AM_Push.p12"; // p12FilePath = "private/AM_Push.p12";
} }
var apnsTopic = "me.myds.ipstein.acamate.AcaMate";
// ApnsPushService 인스턴스 생성
var pushService = new ApnsPushService(uri, p12Path, p12PWPath, apnsTopic); Console.WriteLine($"{uri} || {p12FilePath}");
var pushService = new PushServiceWithP12(keysFilePath, p12FilePath, apnsTopic);
// 푸시 알림 전송 // 푸시 알림 전송
await pushService.SendPushNotificationAsync(deviceToken, payload); await pushService.SendPushAsync(uri, deviceToken, title, body, badge);
return Ok("done");
return Ok("Push notification sent.");
} }
} }

View File

@ -1,65 +1,109 @@
using System; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks;
namespace AcaMate.V1.Services;
using AcaMate.V1.Models; using AcaMate.V1.Models;
using Version = System.Version;
public class ApnsPushService public class PushServiceWithP12
{ {
private readonly string _uri; private readonly string p12Path;
private readonly string _p12Path; private readonly string p12Password;
private readonly string _p12PWPath; private readonly string apnsTopic;
private readonly string _apnsTopic;
public ApnsPushService(string uri,string p12Path, string p12PWPath, string apnsTopic) public PushServiceWithP12(string keysFilePath, string p12Path, string apnsTopic)
{ {
_uri = uri ?? throw new ArgumentNullException(nameof(uri)); // 존재 안하면 예외 던져 버리는거
_p12Path = p12Path ?? throw new ArgumentNullException(nameof(p12Path)); if (!File.Exists(keysFilePath))
_p12PWPath = p12PWPath ?? throw new ArgumentNullException(nameof(p12PWPath)); {
_apnsTopic = apnsTopic ?? throw new ArgumentNullException(nameof(apnsTopic)); Console.WriteLine($"File not found: {keysFilePath}");
throw new FileNotFoundException("The specified file was not found", keysFilePath);
}
var keys = JsonSerializer.Deserialize<Dictionary<string, string>>(File.ReadAllText(keysFilePath));
Console.WriteLine("Keys content:");
foreach (var key in keys)
{
Console.WriteLine($"{key.Key}: {key.Value}");
}
p12Password = keys["Password"];
this.p12Path = p12Path;
this.apnsTopic = apnsTopic;
} }
public async Task SendPushNotificationAsync(string deviceToken, Payload payload) public async Task SendPushAsync(string uri,string deviceToken, string title, string body, int badge)
{ {
var payload = new Payload()
{
aps = new Aps()
{
alert = new Alert()
{
title = title,
body = body
},
badge = badge
}
};
var jsonPayload = JsonSerializer.Serialize(payload); var jsonPayload = JsonSerializer.Serialize(payload);
var keys = JsonSerializer.Deserialize<Dictionary<string, string>>(File.ReadAllText(_p12PWPath)); var handler = new SocketsHttpHandler
var p12Password = keys["Password"]; {
SslOptions = new SslClientAuthenticationOptions
{
EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12 // TLS 1.2 활성화
}
};
try try
{ {
var certificate = new X509Certificate2(_p12Path, p12Password); // .p12 인증서 로드
Console.WriteLine($"Certificate Subject: {certificate.Subject}"); var certificate = new X509Certificate2(p12Path, p12Password,
Console.WriteLine($"Certificate Issuer: {certificate.Issuer}"); X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.PersistKeySet |
X509KeyStorageFlags.Exportable);
handler.SslOptions.ClientCertificates = new X509CertificateCollection { certificate };
Console.WriteLine("Certificate successfully loaded and attached to handler.");
}
catch (CryptographicException ex)
{
Console.WriteLine($"[Error] CryptographicException: {ex.Message}");
throw;
}
catch (Exception ex)
{
Console.WriteLine($"[Error] Unexpected error: {ex.Message}");
throw;
}
var handler = new HttpClientHandler(); using var client = new HttpClient(handler)
handler.ClientCertificates.Add(certificate); {
handler.SslProtocols = System.Security.Authentication.SslProtocols.Tls12; BaseAddress = new Uri($"{uri}")
};
client.DefaultRequestHeaders.ExpectContinue = false;
client.DefaultRequestHeaders.Add("apns-topic", "me.myds.ipstein.acamate.AcaMate");
client.DefaultRequestHeaders.Add("apns-priority", "10");
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
using var client = new HttpClient(handler) try
{ {
BaseAddress = new Uri(_uri),
Timeout = TimeSpan.FromSeconds(60)
};
var request = new HttpRequestMessage(HttpMethod.Post, $"/3/device/{deviceToken}")
{
Content = new StringContent(jsonPayload, Encoding.UTF8, "application/json"),
Version = new Version(2, 0) // HTTP/2 사용
};
// 필수 헤더 추가
request.Headers.Add("apns-topic", _apnsTopic);
request.Headers.Add("apns-push-type", "alert");
Console.WriteLine("Sending push notification...");
Console.WriteLine($"Payload: {jsonPayload}"); Console.WriteLine($"Payload: {jsonPayload}");
Console.WriteLine($"Request URI: {client.BaseAddress}3/device/{deviceToken}");
var response = await client.SendAsync(request);
var response = await client.PostAsync($"3/device/{deviceToken}", content);
Console.WriteLine("이건 넘음?");
if (response.IsSuccessStatusCode) if (response.IsSuccessStatusCode)
{ {
Console.WriteLine("Push notification sent successfully."); Console.WriteLine("Push notification sent successfully.");
@ -67,12 +111,22 @@ public class ApnsPushService
else else
{ {
var errorContent = await response.Content.ReadAsStringAsync(); var errorContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Failed. Status Code: {response.StatusCode}, Error: {errorContent}"); Console.WriteLine($"Failed to send push notification. Status Code: {response.StatusCode}, Error: {errorContent}");
}
}
catch (HttpRequestException httpEx)
{
Console.WriteLine($"HttpRequestException: {httpEx.Message}");
if (httpEx.InnerException != null)
{
Console.WriteLine($"Inner Exception: {httpEx.InnerException.Message}");
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"Error sending push notification: {ex.Message}"); Console.WriteLine($"General Exception: {ex.Message}");
} }
} }
} }