Files
keyboard/keyBoard/Class/Login/VM/KBLoginVM.m
2025-11-17 20:07:39 +08:00

100 lines
4.6 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// KBLoginVM.m
//
#import "KBLoginVM.h"
#import "AppleSignInManager.h"
#import "KBNetworkManager.h"
#import "KBAuthManager.h"
#import "KBAPI.h"
#import "KBUser.h"
@interface KBLoginVM ()
@property (atomic, strong, readwrite, nullable) KBUser *currentUser;
@end
@implementation KBLoginVM
+ (instancetype)shared {
static KBLoginVM *vm; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ vm = [KBLoginVM new]; });
return vm;
}
- (BOOL)isLoggedIn {
return [[KBAuthManager shared] isLoggedIn];
}
- (void)signInWithAppleFromViewController:(UIViewController *)presenter
completion:(KBLoginCompletion)completion {
// 调起 Apple 登录
[[AppleSignInManager shared] signInFromViewController:presenter completion:^(ASAuthorizationAppleIDCredential * _Nullable credential, NSError * _Nullable error) {
if (error) { if (completion) completion(NO, error); return; }
if (![credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
if (completion) completion(NO, [NSError errorWithDomain:@"KBLogin" code:-1 userInfo:@{NSLocalizedDescriptionKey: KBLocalized(@"无效的登录凭证")}]);
return;
}
ASAuthorizationAppleIDCredential *cred = (ASAuthorizationAppleIDCredential *)credential;
// identityToken/authorizationCode 均可按后端要求传递;本项目后端使用 identityToken 映射为 code
NSString *identityToken = cred.identityToken ? [[NSString alloc] initWithData:cred.identityToken encoding:NSUTF8StringEncoding] : nil;
NSString *authorizationCode = cred.authorizationCode ? [[NSString alloc] initWithData:cred.authorizationCode encoding:NSUTF8StringEncoding] : nil;
NSMutableDictionary *params = [NSMutableDictionary dictionary];
if (identityToken.length) params[@"code"] = identityToken;
if (authorizationCode.length) params[@"accessCode"] = authorizationCode; // 仅供后端需要时使用
if (cred.user.length) params[@"userID"] = cred.user; // 可选
// 向服务端发起校验
[[KBNetworkManager shared] POST:API_APPLE_LOGIN jsonBody:params headers:nil completion:^(id _Nullable jsonOrData, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) { if (completion) completion(NO, error); return; }
// 从返回 JSON 中提取 token支持常见命名与层级 data/user
// 先解析用户模型(使用 MJExtension
KBUser *user = [KBUser userFromResponseObject:jsonOrData];
self.currentUser = user;
NSString *token = user.token ?: [self.class tokenFromResponseObject:jsonOrData];
if (token.length == 0) {
if (completion) completion(NO, [NSError errorWithDomain:@"KBLogin" code:-2 userInfo:@{NSLocalizedDescriptionKey: KBLocalized(@"未返回 token")}]);
return;
}
// 保存登录态到共享钥匙串;供 App 与扩展共享
BOOL ok = [[KBAuthManager shared] saveAccessToken:token
refreshToken:nil
expiryDate:nil
userIdentifier:cred.user];
if (completion) completion(ok, ok ? nil : [NSError errorWithDomain:@"KBLogin" code:-3 userInfo:@{NSLocalizedDescriptionKey: KBLocalized(@"保存登录态失败")}]);
}];
}];
}
#pragma mark - Helpers
// 宽松解析token / access_token / accessToken支持顶层或 data/user 层
+ (NSString *)tokenFromResponseObject:(id)obj {
if (![obj isKindOfClass:[NSDictionary class]]) return nil;
NSDictionary *dict = (NSDictionary *)obj;
NSString *(^pick)(NSDictionary *) = ^NSString *(NSDictionary *d) {
NSArray *keys = @[ @"token", @"access_token", @"accessToken" ];
for (NSString *k in keys) {
id v = d[k]; if ([v isKindOfClass:NSString.class] && ((NSString *)v).length > 0) return v;
}
return nil;
};
NSString *t = pick(dict);
if (t.length) return t;
id data = dict[@"data"]; if ([data isKindOfClass:NSDictionary.class]) { t = pick(data); if (t.length) return t; }
id user = dict[@"user"]; if ([user isKindOfClass:NSDictionary.class]) { t = pick(user); if (t.length) return t; }
// 扩展:允许后端将 token 放在 data.session.token
NSDictionary *d2 = dict[@"data"]; if ([d2 isKindOfClass:NSDictionary.class]) {
NSDictionary *session = d2[@"session"]; if ([session isKindOfClass:NSDictionary.class]) { t = pick(session); if (t.length) return t; }
}
return nil;
}
@end