161 lines
5.6 KiB
C#
161 lines
5.6 KiB
C#
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
|
|
namespace AudioWallpaper.SSO {
|
|
|
|
public interface ITokenStore {
|
|
void Save(string tokenName, string token);
|
|
string? Get(string tokenName);
|
|
void Clear(string tokenName);
|
|
}
|
|
public class EncryptedFileTokenStore : ITokenStore {
|
|
private readonly string _storagePath;
|
|
private readonly object _lock = new();
|
|
|
|
public EncryptedFileTokenStore(string storageDirectory) {
|
|
_storagePath = storageDirectory;
|
|
Directory.CreateDirectory(_storagePath);
|
|
}
|
|
|
|
private string GetTokenFilePath(string tokenName) =>
|
|
Path.Combine(_storagePath, $"{tokenName}.token");
|
|
|
|
public void Save(string tokenName, string token) {
|
|
var data = Encoding.UTF8.GetBytes(token);
|
|
var encrypted = ProtectedData.Protect(data, null, DataProtectionScope.CurrentUser);
|
|
|
|
lock (_lock) {
|
|
File.WriteAllBytes(GetTokenFilePath(tokenName), encrypted);
|
|
}
|
|
}
|
|
|
|
public string? Get(string tokenName) {
|
|
var path = GetTokenFilePath(tokenName);
|
|
if (!File.Exists(path))
|
|
return null;
|
|
|
|
try {
|
|
lock (_lock) {
|
|
var encrypted = File.ReadAllBytes(path);
|
|
var decrypted = ProtectedData.Unprotect(encrypted, null, DataProtectionScope.CurrentUser);
|
|
return Encoding.UTF8.GetString(decrypted);
|
|
}
|
|
} catch {
|
|
return null; // 可选:记录日志
|
|
}
|
|
}
|
|
|
|
public void Clear(string tokenName) {
|
|
var path = GetTokenFilePath(tokenName);
|
|
lock (_lock) {
|
|
if (File.Exists(path))
|
|
File.Delete(path);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public class TokenManager {
|
|
private readonly ITokenStore _store;
|
|
|
|
|
|
private const string AccessTokenKey = "access_token";
|
|
private const string RefreshTokenKey = "refresh_token";
|
|
private const string IdTokenKey = "id_token";
|
|
private const string LoginMetaKey = "login_state";
|
|
|
|
public TokenManager(ITokenStore store) {
|
|
_store = store ?? throw new ArgumentNullException(nameof(store));
|
|
}
|
|
|
|
// 保存 TokenSet
|
|
public void SaveToken(TokenSet tokens) {
|
|
SaveToken(tokens, null);
|
|
}
|
|
public void SaveToken(TokenSet tokens, UserInfoSet? userInfoSet) {
|
|
if (tokens == null) throw new ArgumentNullException(nameof(tokens));
|
|
|
|
if (string.IsNullOrWhiteSpace(tokens.AccessToken))
|
|
throw new ArgumentException("Access token is required.");
|
|
if (string.IsNullOrWhiteSpace(tokens.RefreshToken))
|
|
throw new ArgumentException("Refresh token is required.");
|
|
if (string.IsNullOrWhiteSpace(tokens.IdToken))
|
|
throw new ArgumentException("ID token is required.");
|
|
|
|
_store.Save(AccessTokenKey, tokens.AccessToken);
|
|
_store.Save(RefreshTokenKey, tokens.RefreshToken);
|
|
_store.Save(IdTokenKey, tokens.IdToken);
|
|
if (userInfoSet != null) {
|
|
|
|
LoginMeta loginMeta = new LoginMeta {
|
|
IsLoggedIn = true,
|
|
UserInfo = userInfoSet
|
|
};
|
|
SaveLoginMeta(loginMeta);
|
|
}
|
|
}
|
|
public void SaveLoginMeta(LoginMeta? loginMeta) {
|
|
if (loginMeta == null)
|
|
throw new ArgumentNullException(nameof(loginMeta));
|
|
|
|
string loginMetaJson = JsonSerializer.Serialize(loginMeta);
|
|
_store.Save(LoginMetaKey, loginMetaJson);
|
|
|
|
}
|
|
|
|
// 保存单个 token
|
|
public void SaveToken(string name, string token) {
|
|
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Token name is required.");
|
|
if (string.IsNullOrWhiteSpace(token)) throw new ArgumentException("Token value is required.");
|
|
|
|
_store.Save(name, token);
|
|
}
|
|
|
|
// 获取 TokenSet
|
|
public TokenSet? GetToken() {
|
|
var accessToken = _store.Get(AccessTokenKey);
|
|
var refreshToken = _store.Get(RefreshTokenKey);
|
|
var idToken = _store.Get(IdTokenKey);
|
|
|
|
if (string.IsNullOrWhiteSpace(accessToken) && string.IsNullOrWhiteSpace(refreshToken) && string.IsNullOrWhiteSpace(idToken))
|
|
return null;
|
|
return new TokenSet(accessToken ?? string.Empty, refreshToken ?? string.Empty, idToken ?? string.Empty);
|
|
}
|
|
|
|
// 获取指定 token
|
|
public string? GetToken(string name) {
|
|
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Token name is required.");
|
|
return _store.Get(name);
|
|
}
|
|
|
|
// 获取登录状态
|
|
public LoginMeta? GetLoginMeta() {
|
|
var loginMetaJson = _store.Get(LoginMetaKey);
|
|
if (string.IsNullOrWhiteSpace(loginMetaJson))
|
|
return null;
|
|
try {
|
|
return JsonSerializer.Deserialize<LoginMeta>(loginMetaJson);
|
|
} catch (JsonException) {
|
|
return null; // 可选:记录日志
|
|
}
|
|
}
|
|
|
|
// 清除全部 token
|
|
public void ClearToken() {
|
|
_store.Clear(AccessTokenKey);
|
|
_store.Clear(RefreshTokenKey);
|
|
_store.Clear(IdTokenKey);
|
|
_store.Clear(LoginMetaKey);
|
|
}
|
|
|
|
// 清除指定 token
|
|
public void ClearToken(string name) {
|
|
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Token name is required.");
|
|
_store.Clear(name);
|
|
}
|
|
}
|
|
|
|
|
|
}
|