forked from xiongyuxing/tiku-backend.net
feat: add local authentication
This commit is contained in:
56
Tiku.Application/Auth/AuthContracts.cs
Normal file
56
Tiku.Application/Auth/AuthContracts.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using Tiku.Domain.Tenancy;
|
||||
|
||||
namespace Tiku.Application.Auth;
|
||||
|
||||
public sealed record AuthTokenPair(
|
||||
string AccessToken,
|
||||
string RefreshToken,
|
||||
DateTimeOffset AccessTokenExpiresAt,
|
||||
DateTimeOffset RefreshTokenExpiresAt);
|
||||
|
||||
public sealed record TenantMembershipSummary(
|
||||
Guid TenantId,
|
||||
string TenantName,
|
||||
TenantRole Role,
|
||||
MembershipStatus Status);
|
||||
|
||||
public sealed record AuthenticatedUser(
|
||||
Guid UserId,
|
||||
string? Phone,
|
||||
string? Email,
|
||||
string? Name,
|
||||
TenantMembershipSummary Tenant,
|
||||
AuthTokenPair Tokens);
|
||||
|
||||
public sealed record PasswordLoginRequest(
|
||||
Guid TenantId,
|
||||
string Phone,
|
||||
string Password,
|
||||
string? IpAddress,
|
||||
string? UserAgent);
|
||||
|
||||
public sealed record SmsLoginRequest(
|
||||
Guid TenantId,
|
||||
string Phone,
|
||||
string Code,
|
||||
string? IpAddress,
|
||||
string? UserAgent);
|
||||
|
||||
public sealed record RefreshSessionRequest(
|
||||
string RefreshToken,
|
||||
string? IpAddress,
|
||||
string? UserAgent);
|
||||
|
||||
public sealed record LogoutSessionRequest(
|
||||
string RefreshToken);
|
||||
|
||||
public sealed record SmsSendResult(
|
||||
Guid VerificationId,
|
||||
DateTimeOffset ExpiresAt);
|
||||
|
||||
public sealed record SendSmsCodeRequest(
|
||||
Guid TenantId,
|
||||
string Phone,
|
||||
SmsPurpose Purpose,
|
||||
string? IpAddress,
|
||||
string? UserAgent);
|
||||
18
Tiku.Application/Auth/AuthExceptions.cs
Normal file
18
Tiku.Application/Auth/AuthExceptions.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace Tiku.Application.Auth;
|
||||
|
||||
public class AuthException(string code, string message) : Exception(message)
|
||||
{
|
||||
public string Code { get; } = code;
|
||||
}
|
||||
|
||||
public sealed class InvalidCredentialsException(string code = "invalid_credentials")
|
||||
: AuthException(code, "The supplied credentials are invalid.");
|
||||
|
||||
public sealed class TenantAccessDeniedException()
|
||||
: AuthException("tenant_access_denied", "The user is not an active member of the requested tenant.");
|
||||
|
||||
public sealed class SessionRevokedException()
|
||||
: AuthException("session_revoked", "The session has been revoked or expired.");
|
||||
|
||||
public sealed class SmsRateLimitedException()
|
||||
: AuthException("sms_rate_limited", "SMS verification requests are rate limited.");
|
||||
20
Tiku.Application/Auth/IAuthService.cs
Normal file
20
Tiku.Application/Auth/IAuthService.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace Tiku.Application.Auth;
|
||||
|
||||
public interface IAuthService
|
||||
{
|
||||
Task<AuthenticatedUser> LoginWithPasswordAsync(
|
||||
PasswordLoginRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<AuthenticatedUser> LoginWithSmsAsync(
|
||||
SmsLoginRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<AuthTokenPair> RefreshAsync(
|
||||
RefreshSessionRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task LogoutAsync(
|
||||
LogoutSessionRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
7
Tiku.Application/Auth/IPasswordHasher.cs
Normal file
7
Tiku.Application/Auth/IPasswordHasher.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Tiku.Application.Auth;
|
||||
|
||||
public interface IPasswordHasher
|
||||
{
|
||||
string Hash(string password);
|
||||
bool Verify(string password, string passwordHash);
|
||||
}
|
||||
19
Tiku.Application/Auth/ISessionService.cs
Normal file
19
Tiku.Application/Auth/ISessionService.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Tiku.Domain.Tenancy;
|
||||
|
||||
namespace Tiku.Application.Auth;
|
||||
|
||||
public interface ISessionService
|
||||
{
|
||||
string GenerateRefreshToken();
|
||||
string HashRefreshToken(string refreshToken);
|
||||
|
||||
Task<AuthTokenPair> IssueAsync(
|
||||
Guid userId,
|
||||
string? phone,
|
||||
string? email,
|
||||
TenantMembership membership,
|
||||
string provider,
|
||||
string? ipAddress,
|
||||
string? userAgent,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
17
Tiku.Application/Auth/ISmsVerificationService.cs
Normal file
17
Tiku.Application/Auth/ISmsVerificationService.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Tiku.Domain.Tenancy;
|
||||
|
||||
namespace Tiku.Application.Auth;
|
||||
|
||||
public interface ISmsVerificationService
|
||||
{
|
||||
Task<SmsSendResult> CreateCodeAsync(
|
||||
SendSmsCodeRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task VerifyCodeAsync(
|
||||
Guid tenantId,
|
||||
string phone,
|
||||
SmsPurpose purpose,
|
||||
string code,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
13
Tiku.Application/Auth/ITokenService.cs
Normal file
13
Tiku.Application/Auth/ITokenService.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Tiku.Domain.Tenancy;
|
||||
|
||||
namespace Tiku.Application.Auth;
|
||||
|
||||
public interface ITokenService
|
||||
{
|
||||
(string Token, DateTimeOffset ExpiresAt) CreateAccessToken(
|
||||
Guid userId,
|
||||
Guid sessionId,
|
||||
string? phone,
|
||||
string? email,
|
||||
TenantMembership membership);
|
||||
}
|
||||
10
Tiku.Application/Security/JwtOptions.cs
Normal file
10
Tiku.Application/Security/JwtOptions.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Tiku.Application.Security;
|
||||
|
||||
public sealed class JwtOptions
|
||||
{
|
||||
public string Issuer { get; set; } = "tiku-backend";
|
||||
public string Audience { get; set; } = "tiku-api";
|
||||
public string SigningKey { get; set; } = "development-only-tiku-signing-key-change-before-production";
|
||||
public int AccessTokenMinutes { get; set; } = 30;
|
||||
public int RefreshTokenDays { get; set; } = 30;
|
||||
}
|
||||
Reference in New Issue
Block a user