Proceso de inicio de sesión del lado de la aplicación: abra la aplicación, si el token no caduca, use el último token de inicio de sesión para realizar una solicitud de interfaz

¡Acostúmbrate a escribir juntos! Este es el día 16 de mi participación en el "Desafío de actualización de abril del nuevo plan diario de Nuggets", haga clic para ver los detalles del evento .

Requisitos previos

1.1 Sesión bajo sistema distribuido

inserte la descripción de la imagen aquí

session: un mecanismo para guardar claves de valor-clave:

  1. ID de sesión
  2. token (usado con firma)

inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí

1.2 Procesamiento de inicio de sesión en el lado del servidor

  1. openid para que coincida con los datos en la base de datos (usando el inicio de sesión autorizado de WeChat)
  2. establecer el token en redis
  3. establecer token en cookie

1.3 Requisitos del lado de la aplicación

  1. Cuando la aplicación se inicia en frío, si el token no caduca, el último token de inicio de sesión se usa para la solicitud de datos

  2. Optimice el método de almacenamiento de tokens:

Solo se almacenó en la memoria antes, siempre que la aplicación se elimine y se vuelva a abrir, requiere volver a iniciar sesión. Ahora almacene la información del token en la base de datos local y use el token obtenido del inicio de sesión más reciente cada vez que se abre la aplicación.

Proceso de inicio de sesión del lado de la aplicación II

2.1 Pasos de desarrollo

  • I. Guarde el token en el objeto UserInfoModel
  • II. Obtenga el token cuando vuelva a abrir la aplicación
  • III. Cierre de sesión o invalidación (token) para borrar información
  • IV. Determinar si ingresar a la página de inicio directamente en viewDidLoad de la interfaz de inicio de sesión
  • V: El almacenamiento de token distingue entre el entorno formal y el entorno de prueba (el objeto UserInfoModel agrega un atributo de nombre de dominio currentHost del token actual, que se usa para el juicio de consulta) 5.1) Cambia el nombre de la tabla 5.2) UserInfoModel agrega un nuevo campo currentHost , 5.3) Query token agrega una nueva condición currentHost 5.4 ) para almacenar el nuevo campo currentHost del token

2.2 Precauciones para el almacenamiento de información de tokens

La información del token obtenida al iniciar sesión en la cuenta. Es mejor no almacenarlo como un objeto de interés simple independiente; en su lugar, utilícelo como el atributo userInfo del objeto singleton, lo cual es conveniente para cambiar cuentas para almacenar tokens y otra información de cuenta.

  • Si usó un objeto UserInfoModel de interés simple separado antes, puede hacerlo para compatibilidad de código
/**
 登录账号得到的token信息。最好不要作为一个独立的单利对象存储;而是将它作为单例对象的属性userInfo,便于切换账号存储token和其他账号信息。
 */
+ (instancetype)shareUserInfoModel{
    
    return [QCTSession.shareQCTSession userInfo];
    
}


复制代码

使用线程安全模式来创建共享实例,并使用条件编译#if进行ARC、MRC的适配

kunnan.blog.csdn.net/article/det…

2.3 整体思路

保存和清除token

  • 使用BGFMDB 进保存最近一次登录的token
pod 'BGFMDB', '~> 2.0.13'  #2.0.9
复制代码
  • 切换账号的时候更换token
  • 请求接口发现token 失效的时候,回到登录界面

III 核心实现

3.1 Session 对象的创建

使用HSSingleton工具类实现单例,并将包含登陆token及其他有状态相关字段的userInfo对象作为单例对象的属性

HSSingletonH(Session);
HSSingletonM(Session);

+ (void)SaveUserInfo:(UserInfoModel *)userInfo{
    
    QCTSession.shareQCTSession.userInfo = userInfo;
}

复制代码

存储token信息

#pragma mark - ******** iOS 优化登录流程:【打开app,如果 token不过期,就使用最近一次登录的tokenn进行接口请求。】(现状是每次打开app都会重新登录)

+ (void)saveModelWithModel:(UserInfoModel*)userModel{
    [self emptySeeionLocal];

    
    userModel.bg_tableName = QCTUserInfoModelTableName;
    
    BOOL isSave = [userModel bg_save];// 保存方法
    if (isSave) {
        NSLog(@"token保存成功:%@",userModel.mj_keyValues);
        
        
    }else{
        NSLog(@"token保存失败:%@",userModel.mj_keyValues);
        
        
    }
    
    
}

+(void)emptySeeionLocal{
    
    
    NSMutableArray *tmparr = [NSMutableArray arrayWithArray:[[self class] bg_find:QCTUserInfoModelTableName where:nil] ];
    
    
    // 先删除
    
    for (UserInfoModel *loginModel in tmparr) {
        NSString *where = [NSString stringWithFormat:@"where %@=%@",bg_sqlKey(@"bg_id"),bg_sqlValue(loginModel.bg_id)];
        
        
        BOOL isDelete = [UserInfoModel bg_delete:[NSString stringWithFormat:@"%@",QCTUserInfoModelTableName] where:where];
        NSLog(@"删除重复数据%@:%@",isDelete?@"成功":@"失败",loginModel.mj_keyValues);
        //            break;
        //
    }

}

复制代码

获取token信息

+ (instancetype)getmodel4LoginSeesion{
    
    
    NSMutableArray *tmparr = [NSMutableArray arrayWithArray:[[self class] bg_find:QCTUserInfoModelTableName where:nil] ];
    
    
    
    
    if(tmparr.count>0   ){
        UserInfoModel *userModel = tmparr.firstObject;
//        QCTSession.shareQCTSession.userInfo = userModel;
        
        [ QCTSession SaveUserInfo:userModel];
        
        NSLog(@"获取的token 信息%@",userModel);

        
        return tmparr.firstObject;
        
    }
    
    NSLog(@"获取的token userModel.shareUserInfoModel %@",UserInfoModel.shareUserInfoModel);
    
    
    //

    return UserInfoModel.shareUserInfoModel;
    
    
}

复制代码

3.2 保存token到UserInfoModel 对象中的时机

  • 登录的时候
 [ Session SaveUserInfo:userModel];

 [UserInfoModel saveModelWithModel:userModel];

复制代码
  • app 退出的时候:applicationWillTerminate 、applicationWillResignActive
- (void)applicationWillTerminate:(UIApplication *)application {
    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    [UserInfoModel saveModelWithModel:UserInfoModel.shareUserInfoModel];
    
    

}

复制代码

3.3 再次打开app的时候获取token

#pragma mark - ******** 获取token信息

- (void)initInfo{
    
    QCTSession.shareQCTSession.tmpUserInfoModel = nil;
        
    [UserInfoModel getmodel4LoginSeesion];// 获取会话
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [self initInfo];
}
复制代码

3.4 退出登录或者(token)失效进行信息信息清除

  • 在 application :didFinishLaunchingWithOptions: 方法进行监听
    __weak __typeof__(self) weakSelf = self;

    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:kExitlogshowLoginViewNotification object:nil] subscribeNext:^(NSNotification *notification) {
        
        
        NSString *tmp = @"";
        
        if(notification.object){
            
            tmp = notification.object;
            
            [weakSelf.window showHUDMessage:tmp afterBlock:^(id  _Nonnull sender) {
                [weakSelf setupExitlogout];
                
            }];
            

            
            
            
        }else{
//            tmp = @"";
            
            [weakSelf setupExitlogout];

            
        }
        
        
        
        
        
    }];


复制代码
  • 退出登录(token过期)的处理
/**
 1、移除极光的别名
 2、初始化一些信息
 3、清除账户信息缓存(本地数据库和内存中的token信息)
 
 */
- (void)setupExitlogout
{
    [JPUSHService setTags:nil alias:@"" callbackSelector:@selector(tagsAliasCallback:tags:alias:) object:self];
    
    [UserInfoModel cleanInfoWithblock:^(id sender) {
        
        //3、登录
            UserInfoModel.shareUserInfoModel.token = nil;
        
        AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
        [appDelegate setupLoginV];

    }];



}

复制代码
  • 清除本地数据库的token
+ (void)cleanInfoWithblock:(void (^)(id sender))block{
    
    
    [[UserInfoModel shareUserInfoModel] cleanInfo];
    

    
    
    if(block){
        block(nil);
    }
    
    
}
- (void)cleanInfo{
#pragma mark - ******** 包括清除本地数据库的token
    [[self class] emptySeeionLocal];//

        [self  setToken:nil];
        
        _CurrentSysUser = nil;
    //    _
    [QCTSession shareQCTSession].tmpUserInfoModel = nil;
    

}

复制代码

3.5 在登录界面的viewDidLoad 进行判断是否直接进入首页

  • viewDidLoad 早createSubView的时候进行判断,是否直接进入首页
        if(UserInfoModel.shareUserInfoModel.isLoginByToken){
            
            
            [[self class] jumpHome];
            
            
            return;
        }
复制代码
  • 判断是否有token
/**
 判断是否有token
 */
- (BOOL)isLoginByToken{
    
    
    if(![NSStringQCTtoll isBlankString:UserInfoModel.shareUserInfoModel.token]){
                
        
        return YES;
    }
    
    return NO;


}

复制代码

3.6 token存储区分正式环境和测试环境

  • UserInfoModel 对象新增一个当前token的域名属性currentHost,用于查询判断环境

  • BGFMDB如果新增字段,就需要更换一下表名

#warning  BGFMDB如果新增字段,就需要更换一下表名,否则在旧表会找不到字段,无法更新数据
 2021-01-29 17:16:10.418453+0800 Housekeeper[15013:1071895] [logging] table QCTUserInfoModelTableName0401 has no column named BG_IsreqGetCurrentSysUsering in "insert into QCTUserInfoModelTableName0401(BG_currentHost,BG_BearerToken,BG_token,BG_DictionariesEnum,BG_DictionariesEnumDictionary,BG_loginCode,BG_isGotoChangePassword,BG_HaveDefaultLevel,BG_bg_updateTime,BG_loginMessage,BG_IsreqGetCurrentSysUsering,BG_IsTobacco,BG_bg_createTime,BG_MsgsourceStr,BG_isShowBindingMobileNote) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);"

复制代码
  • 根据域名进行存取token的

inserte la descripción de la imagen aquí

    NSString*  where = [NSString stringWithFormat:@"where %@=%@",bg_sqlKey(@"currentHost"),bg_sqlValue(currentHost)];
   NSMutableArray *tmparr = [NSMutableArray arrayWithArray:[[self class] bg_find:QCTUserInfoModelTableName where:where] ];
复制代码

存储token信息

+ (void)saveModelWithModel:(UserInfoModel*)userModel{
    [self emptySeeionLocal];

    
    userModel.bg_tableName = QCTUserInfoModelTableName;
    
    userModel.currentHost = currentHost;
    

    BOOL isSave = [userModel bg_save];// 保存方法
    if (isSave) {
        NSLog(@"token保存成功:%@",userModel.mj_keyValues);
        
        
    }else{
        NSLog(@"token保存失败:%@",userModel.mj_keyValues);
        
        
    }
    
    
}

复制代码

3.7 注意事项

  • `2020-03-30 19:23:12.877204+0800 Housekeeper[5577:1118700] DB Error: 1 "duplicate column name: BG_CompanyId"

` BGFMDB 不支持大小写,因此保存的对象不能有大小写的两个字段

@property (copy, nonatomic) NSString *companyId;
//@property (strong, nonatomic) NSString *CompanyId;

复制代码
  • `2020-04-01 16:18:32.127564+0800 retail[8875:1402725] [registro] tabla QCTUserInfoModelTableName no tiene ninguna columna llamada BG_currentHost

`

Consejos de depuración

Si se agrega un nuevo campo a la tabla de BGFMDB, puede cambiar el nombre de la tabla para evitar encontrar el campo y no poder actualizar los datos.

Si agrega un nuevo campo, debe cambiar el nombre de la tabla

IV ver también

Número público: iOS inverso

おすすめ

転載: juejin.im/post/7086991137746976798