php和app保持登录状态,关于iOS开发者中APP保持登录状态的几种实现方式和一些思考...

在实际开发中几乎所有的APP都会存在用户体系,假如没有涉及用户体系的APP,提交审核的时候有很大概率会被苹果爹地直接拒绝不允许上架。而有了用户体系,那么就肯定会存在登录以及保持登录的需求,要不然用户每次启动APP都得重新登录,那就乖乖了。保持登录状态的方式目前大致有以下几种方式:

一、利用Cookie机制实现

我们知道cookie是为了解决http无状态的一种技术,被电商、oa等web应用广泛使用。如果我们的App和后端通讯采用的http通讯方式,可以利用cookie技术进行登录状态保持。比如我们可以把sessionID和有效期保存在cookie中,发给前端App,前端App收到后保存在本地。当访问后端服务把sessionID和有效期作为参数传给后台进行认证。直到sessionID失效,用户都不需要重新登录。

二、本地保存用户名和密码

当用户第一次输入账号和密码的时候,APP端本地保存用户的账号和密码,下次启动的时候获取本地保存的账户和密码进行登录,由我们开发者在后台进行登录处理,不过这个有个不是太合适的就是相当于在APP本地保存了用户的这些信息,意义上来说不安全,不过大致的实现方式如下:

1、在登陆页面对应的类loginViewController.h中定义两个TextField和一个Button,用来接受用户输入的用户名和密码,点击按钮登陆,如果登陆成功,就将用户的登陆信息存放在UserDefault中,然后跳入主页面。

@interface LoginViewController ()

@property (nonatomic, strong) UITextField *username;

@property (nonatomic, strong) UITextField *password;

@end

2、在loginViewController.m中实现两个TextField和一个Button,直接实现按钮的点击登录事件:登录请求成功后,走成功回调,回调下面实现将用户名和密码存入UserDefault中,页面跳转到主页面。下面数据请求的代码略去了,直接上存储UserDefault代码,跳转主页面。

NSString *username = self.username.text;

NSString *password = self.password.text;

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

[userDefaults setObject:username forKey:@"username"];

[userDefaults setObject:password forKey:@"password"];

[userDefaults synchronize];

UITabBarController *tabBarVc = [[UITabBarController alloc] init];

UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:tabBarVc];

AppDelegate *appdelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;

appdelegate.window.rootViewController = nc;

3、在AppDelegate.m中实现:用户第一次进入APP时自动进入登录注册页,提示用户注册登录,用户登录成功后才进入主页,再次进入APP时,不用再次登录就直接进到主页了

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

//初始化Window

self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

self.window.backgroundColor = [UIColor whiteColor];

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

if (![userDefaults objectForKey:@"username"]){

//进入主页

UITabBarController *tabbarVc = [[UITabBarController alloc]init];

UINavigationController *navVc = [[UINavigationController alloc]initWithRootViewController:tabbarVc];

self.window.rootViewController = navVc;

} else {

//进入登录页面

LoginViewController *loginVc = [[LoginViewController alloc] init];

[self.navController pushViewController:loginVc animated:YES];

}

[self.window makeKeyWindow];

return YES;

}

4、退出登录

//退出登录,清除用户信息

- (void)logout{

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

[userDefaults removeObjectForKey:@"username"];

[userDefaults removeObjectForKey:@"password"];

//跳转登陆页

LoginViewController *loginVc = [[LoginViewController alloc] init];

[self.navController pushViewController:loginVc animated:YES];

}

三、前后端配合采用token方式

token方式在app认证上用的比较普遍,App初始登录时,提交账号和密码数据给服务端,服务端根据定义的的策略生成一个token字符串,token字符串中可以包含用户信息、设备ID等信息以保证用户的唯一性,服务端并对token设置一定的期限。服务端把生成的token字符串传给客户端,客户端保存token字符串,并在接下来的请求中带上这个字符串。相对于在App本地token的安全性更高了。

说明:这里说说关于设备唯一ID的小细节,如果直接把设备唯一ID传给后台的话,这里可能会出现一个问题,比如在同一台手机退出登录后再登录其他账号,那么就会出现多个账号的设备ID就都一样了。这样会带来什么后果呢?比如如果还使用极光推送的话,用这个设备ID注册别名的话,那么就会出现多个账号的别名都是一样的,那么推送就乱了。

//uuid + 手机 + iOS

NSString *uuid = [[GetUUID getUUID] stringByReplacingOccurrencesOfString:@"-" withString:@""];

//截取UUID的后十位

NSString *uuidPart = [uuid substringFromIndex:uuid.length - 10];

NSString *aliasStr = [NSString stringWithFormat:@"%@_%@_iOS",uuidPart,phoneNum];

上面就是我在实际开发使用设备ID唯一性的处理,就是UUID + 手机号码 + iOS(平台),安卓就是UUID + 手机号码 + Android。这样子就不仅避免了同一台设备登录多个账号的问题,还区分了不同平台登录的账号。

1、用户第一次登录之后本地保存token

[[NSUserDefaults standardUserDefaults] setObject:[responseObject.data objectForKey:@"token"] forKey:token];

[[NSUserDefaults standardUserDefaults] synchronize];

2、再次启动的时候获取本地保存的token

NSString *token = [[NSUserDefaults standardUserDefaults] objectForKey:token];

然后用这个token请求一个后台验证该token是否在有效期的接口,接着根据后台返回的信息进行相关页面的跳转处理。

到此为止,目前几种保持登录状态的方法大致介绍完了,不知道细心的你有没有发现一个小细节,那就是很多都是采用根据登录状态是否有效来设置window的rootViewController根控制器,就是说没有登录状态下rootViewController是loginViewController登录页,有登录状态有效的情况下rootViewController是navVC导航控制器或者其他UIViewController控制器等,如下:

if(有登录状态){

BaseTabBarViewController *baseVc = [[BaseTabBarViewController alloc] init];

self.window.rootViewController = baseVc;

}else{

LoginViewController *loginVc = [[LoginViewController alloc] init];

self.window.rootViewController = loginVc;

}

但是有一种比较特殊的情况,其实也不特殊,就是也是一种产品形式,那就是不管有没有登录状态下,window的rootViewController都是BaseTabBarViewController,就是说不会随着登录状态失效根控制器进行更换,因为很多APP也都存在游客模式,就是不用登录状态也可以进入APP进行基础的操作,而当点击到需要登陆地方时没有登录状态的话就跳转到登录页,有的话就继续下一步操作,那么这个时候我们应该怎么处理呢?下面继续说说暂时个人想到的处理方式:

处理方式1:

首先设置window的rootViewController根控制器为BaseViewController(UIViewController类型的),然后再立即获取用户的登录状态是否有效,不管登录状态是否有效都会把window的rootViewController设置为BaseTabBarViewController,只是在获取到用户登录状态信息之后BaseTabBarViewController里的有些UI展示不一样,直接上代码:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

//token登录

[self initService];

//先创建根控制器,然后会在AppDelegate+AppService分类中进行根控制器的替换

self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

//先进行网络监测防止手机开启飞行模式时进入白屏

if (![XMFUserHttpHelper checkNetStatus]) {

XMFTabBarViewController *baseVc = [[XMFTabBarViewController alloc] init];

self.window.rootViewController = baseVc;

}else{

XMFBaseViewController *baseVc = [[XMFBaseViewController alloc] init];

self.window.rootViewController = baseVc;

}

[self.window makeKeyAndVisible];

}

//初始化服务

-(void)initService{

NSString *token = [[NSUserDefaults standardUserDefaults] objectForKey:token];

if (![sessionId isBlankString]) {//先判断是否是空字符串

//获取保存的token供下面接口的头部使用

[XMFGlobleManager getGlobleManager].token = token;

[SVProgressHUD show];

[[XMFUserHttpHelper sharedManager] sessionLoginCheckWithParam:nil success:^(XMFResponseModel *responseObject) {

[SVProgressHUD dismiss];

//token在有效期内

if (responseObject.returnCode == XMFHttpReturnCodeSuccess) {

token = [responseObject.data objectForKey:@"token"];

[XMFGlobleManager getGlobleManager].isLogin = YES;

//发送登录成功的通知

[[NSNotificationCenter defaultCenter] postNotificationName:DWQ_NOTIFY_LoginState_Change object:@YES userInfo:nil];

[[NSUserDefaults standardUserDefaults] setObject:[responseObject.data objectForKey:@"token"] forKey:token];

[[NSUserDefaults standardUserDefaults] synchronize];

[self setRootViewController];

}else{

[self setRootViewController];

//登录失败

[[NSNotificationCenter defaultCenter] postNotificationName:DWQ_NOTIFY_LoginState_Change object:@NO userInfo:nil];

}

} failure:^(NSError *error) {

[self setRootViewController];

}];

}else{

[self setRootViewController];

}

}

//等待验证token是否有效之后进行设置根控制器

-(void)setRootViewController{

XMFTabBarViewController *tabvc = [[XMFTabBarViewController alloc] init];

self.window.rootViewController = tabvc;

}

这样子大致就把不管有无登录状态rootViewController都为XMFTabBarViewController的情况处理好了,不过这里面还有一个小细节会影响体验,仔细看看上面是不是登录状态是否有效取决于后台返回,网络请求快的情况下可能感受不到,那万一网络请求缓慢的话,那就会出现用户会在等待AFHTTPSessionManager的manager.requestSerializer.timeoutInterval = 20;时间之后才出现了XMFTabBarViewController,这样的体验是有点影响的,那么再来继续优化一下。

处理方式2:

这里直接不管是否有登录状态都直接设置window的rootViewController为XMFTabBarViewController,代码如下:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

//token登录

[self initService];

//先创建根控制器,然后会在AppDelegate+AppService分类中进行根控制器的替换

self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

ZFTabBarViewController *baseVc = [[ZFTabBarViewController alloc] init];

self.window.rootViewController = baseVc;

[self.window makeKeyAndVisible];

}

//初始化服务

-(void)initService{

NSString *token = [[NSUserDefaults standardUserDefaults] objectForKey:token];

if (![sessionId isBlankString]) {//先判断是否是空字符串

//获取保存的token供下面接口的头部使用

[XMFGlobleManager getGlobleManager].token = token;

[SVProgressHUD show];

[[XMFUserHttpHelper sharedManager] sessionLoginCheckWithParam:nil success:^(XMFResponseModel *responseObject) {

[SVProgressHUD dismiss];

//token在有效期内

if (responseObject.returnCode == XMFHttpReturnCodeSuccess) {

token = [responseObject.data objectForKey:@"token"];

[XMFGlobleManager getGlobleManager].isLogin = YES;

//发送登录成功的通知

[[NSNotificationCenter defaultCenter] postNotificationName:DWQ_NOTIFY_LoginState_Change object:@YES userInfo:nil];

[[NSUserDefaults standardUserDefaults] setObject:[responseObject.data objectForKey:@"token"] forKey:token];

[[NSUserDefaults standardUserDefaults] synchronize];

}else{

//登录失败

[[NSNotificationCenter defaultCenter] postNotificationName:DWQ_NOTIFY_LoginState_Change object:@NO userInfo:nil];

}

} failure:^(NSError *error) {

}];

}

}

然后在会随着登录状态改变UI界面的页面进行对“isLogin”属性进行kvo监测,接着进行相应的UI改变,代码如下:

- (void)viewWillAppear:(BOOL)animated{

[super viewWillAppear:animated];

//增加对登录状态"isLogin"值变化的观察

kWeakSelf(self)

[JJKeyValueObserver addObserveObject:[XMFGlobleManager getGlobleManager] keyPath:@"isLogin" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew changeBlock:^(NSDictionary *dict) {

// DLog(@"登录状态发生了改变:%@",[dict description]);

weakself.rightLoginBtn.selected = [XMFGlobleManager getGlobleManager].isLogin;

}];

}

同时博主的kvo使用的是第三方JJKeyValueObserver,大家有需要的可以去GitHub上下载使用,也可以自己实现kvo,原理是一样的。那经过这么一番处理之后,整个保持登录的过程差不多就处理完了,同时博主开发中采用的是“前后端配合采用token方式”。

如果以上的分享帮助到你了,欢迎分享,更欢迎赞赏,也可以直接打开支付宝、微信、QQ的扫一扫功能直接扫下面的支付宝、微信、QQ三合一打赏码进行打赏支持作者创作,感谢感谢!

16101cf2de62

image

欢迎和我交流,QQ:834537795(小蜜蜂)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值