新浪微博客户端(15)-保存用户名和密码

检测本地是否保存有用户的密码。如果有,则下次自动登录;如果没有,则提示用户登录。

DJAccount.h

#import <Foundation/Foundation.h>

@interface DJAccount : NSObject

/** 访问token */
@property (nonatomic,copy) NSString *access_token;
/** 过期时间,单位是秒 */
@property (nonatomic,copy) NSNumber *expires_in;
/** 当前user id */
@property (nonatomic,copy) NSString *uid;
/** 当前帐号创建时间 */
@property (nonatomic,strong) NSDate *create_time;

+ (instancetype)accountWithDictionary:(NSDictionary *)dict;

@end

DJAccount.m

#import "DJAccount.h"

@interface DJAccount() <NSCoding>

@end

@implementation DJAccount

+ (instancetype)accountWithDictionary:(NSDictionary *)dict {

    DJAccount *account = [[DJAccount alloc] init];

    account.access_token = dict[@"access_token"];
    account.expires_in = dict[@"expires_in"];
    account.uid = dict[@"uid"];
    account.create_time = [NSDate date];

    return account;
}

- (void)encodeWithCoder:(NSCoder *)encoder {

    [encoder encodeObject:self.access_token forKey:@"access_token"];
    [encoder encodeObject:self.expires_in forKey:@"expires_in"];
    [encoder encodeObject:self.uid forKey:@"uid"];
    [encoder encodeObject:self.create_time forKey:@"create_time"];

}

- (instancetype)initWithCoder:(NSCoder *)decoder {

    if (self = [super init]) {
        self.access_token = [decoder decodeObjectForKey:@"access_token"];
        self.expires_in = [decoder decodeObjectForKey:@"expires_in"];
        self.uid = [decoder decodeObjectForKey:@"uid"];
        self.create_time = [decoder decodeObjectForKey:@"create_time"];
    }
    return self;

}

@end

DJAccountTool.h

#import <Foundation/Foundation.h>

@class DJAccount;

@interface DJAccountTool : NSObject

+ (void)saveAccount:(DJAccount *)account;

+ (DJAccount *)account;

@end

DJAccountTool.m

#import "DJAccountTool.h"
#import "DJAccount.h"

#define DJAccountPath [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"account.archiver"]

@implementation DJAccountTool

+ (void)saveAccount:(DJAccount *)account {

    [NSKeyedArchiver archiveRootObject:account toFile:DJAccountPath];

}

+ (DJAccount *)account {

    DJAccount *account = [NSKeyedUnarchiver unarchiveObjectWithFile:DJAccountPath];
    // 判断当前帐号是否过期
    long long expires_in = [account.expires_in longLongValue];
    // 获得过期时间
    NSDate *expires_time = [account.create_time dateByAddingTimeInterval:expires_in];
    // 获得当前时间
    NSDate *now_time = [NSDate date];
    // 如果now大于expires_time,则代表过期
    NSComparisonResult result = [expires_time compare:now_time];
    if (result != NSOrderedDescending) {
        return nil;
    }
    return account;
}

@end

UIWindow+Extension.m

#import "UIWindow+Extension.h"
#import "DJMainViewController.h"
#import "DJNewFeatureViewController.h"

@implementation UIWindow (Extension)

+ (void)switchRootViewController {

    // 获取当前主窗口
    UIWindow *window = [UIApplication sharedApplication].keyWindow;

    NSString *versionKey = @"CFBundleVersion";
    // 从Info.plist中读取当前软件版本号
    NSString *currentVersion = [NSBundle mainBundle].infoDictionary[versionKey];
    // 从沙盒中读取保存的历史版本号
    NSString *lastVersion = [[NSUserDefaults standardUserDefaults] objectForKey:versionKey];

    // 判断当前软件版本号是否与沙盒中保存的一致
    if ([currentVersion isEqualToString:lastVersion]) { // 版本号一致
        DJMainViewController *mainVc = [[DJMainViewController alloc] init];
        window.rootViewController = mainVc;
    } else { // 版本号不一致,显示新特性,并将当前软件版本号保存到沙盒
        /* 1.显示新特性 */
        DJNewFeatureViewController *newVc = [[DJNewFeatureViewController alloc] init];
        window.rootViewController = newVc;
        /* 2.将当前版本号写入到沙盒 */
        [[NSUserDefaults standardUserDefaults] setValue:currentVersion forKey:versionKey];
        // 立即将内存中的数据同步到沙盒
        [[NSUserDefaults standardUserDefaults] synchronize];
    }

}

@end

AppDelegate.m

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

    // 1. 创建窗口
    self.window = [[UIWindow alloc] init];
    self.window.frame = [UIScreen mainScreen].bounds;

    // 2. 显示窗口
    [self.window makeKeyAndVisible];

    // 3. 判断当前帐户是否已经被授权来决定根控制器显示
    DJAccount *account = [DJAccountTool account];
    if (account) { // 之前已经成功授权
        [UIWindow switchRootViewController];
    } else { // 尚未成功授权
       self.window.rootViewController = [[DJOAuthViewController alloc] init];
    }

    return YES;
}

DJOAuthViewController.m

#import "DJOAuthViewController.h"
#import "AFNetworking.h"
#import "DJAccount.h"
#import "DJAccountTool.h"
#import "MBProgressHUD+MJ.h"

@interface DJOAuthViewController () <UIWebViewDelegate>

@end

@implementation DJOAuthViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    /* client_id&redirect_uri */
    NSString *client_id = @"249054863";
    NSString *redirect_uri = @"https://www.baidu.com";

    UIWebView *webView = [[UIWebView alloc] init];
    webView.frame = self.view.bounds;
    webView.delegate = self;

    [self.view addSubview:webView];

    NSString *urlString = [NSString stringWithFormat:@"https://api.weibo.com/oauth2/authorize?client_id=%@&redirect_uri=%@",client_id,redirect_uri];

    NSURL *url = [NSURL URLWithString:urlString];
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];

    [webView loadRequest:urlRequest];

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - webView 代理方法

- (void)webViewDidStartLoad:(UIWebView *)webView {
    [MBProgressHUD showMessage:@"加载中..."];

}

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    [MBProgressHUD hideHUD];
}

/** 此方法可用于拦截http请求 */
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    NSString *urlString = request.URL.absoluteString;
    DJLog(@"current access url str : %@",urlString);

    // 1. 判断当前地址是否是回调地址(https://www.baidu.com/?code=27a3d9fb9bbc5d3c20be9ae8e4331b02)
    NSRange range= [urlString rangeOfString:@"code="];
    if (range.length != 0) { // 是回调地址
        // 2.截取code=后面的参数值
        NSUInteger fromIndex = range.location + range.length;
        NSString *code = [urlString substringFromIndex:fromIndex]; // code 就是授权成功的请求标记
        // 3.使用授权成功的请求标记(code)来换取accessToken
        [self getAccessTokenWithCode:code];
        // 4.禁止加载回调地址
        return NO;
    }

    return YES;
}

- (void)getAccessTokenWithCode:(NSString *)code {

    // 1. 创建请求管理者
    AFHTTPSessionManager *requestManager = [AFHTTPSessionManager manager];

    // 2. 配置请求参数
    NSString *urlString = @"https://api.weibo.com/oauth2/access_token"; // 请求授权的access_token URL
    NSMutableDictionary *params = [NSMutableDictionary dictionary];
    params[@"client_id"] = @"249054863";
    params[@"client_secret"] = @"71d5b761bac9f377af3b938f6d89ba85";
    params[@"grant_type"] = @"authorization_code";
    params[@"code"] = code;
    params[@"redirect_uri"] = @"https://www.baidu.com";

    // 3. 发送请求
    [requestManager POST:urlString parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, NSDictionary *  _Nullable dict) {

        [MBProgressHUD hideHUD];
        // 1. 将返回的字典转换为模型
        DJAccount *account = [DJAccount accountWithDictionary:dict];
        // 2. 存储当前帐号信息
        [DJAccountTool saveAccount:account];
        // 3. 切换根控制器到DJMainViewController
        [UIWindow switchRootViewController];

    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [MBProgressHUD showError:@"授权失败"];
         DJLog(@"failure responseObject: %@",error);
    }];

}

@end

最终效果:

时间: 2024-10-10 14:15:33

新浪微博客户端(15)-保存用户名和密码的相关文章

TortoiseSVN客户端不能记住用户名和密码

TortoiseSVN客户端重新设置用户名和密码 在第一次使用TortoiseSVN从服务器CheckOut的时候,会要求输入用户名和密码,这时输入框下面有个选项是保存认证信息,如果选了这个选项,那么以后就不用每次都输入一遍用户名密码了. 不过,如果后来在服务器端修改了用户名密码,则再次检出时就会出错,而且这个客户端很弱智,出错之后不会自动跳出用户名密码输入框让人更新,我找了半天也没找到修改这个用户名密码的地方. 最终,找到两种解决办法: 办法一:在TortoiseSVN的设置对话框中,选择“已

使用keychain保存用户名和密码等敏感信息 KeychainItemWrapper和SFHFKeychainUtils

iOS的keychain服务提供了一种安全的保存私密信息(密码,序列号,证书等)的方式,每个ios程序都有一个独立的keychain存储.相对于 NSUserDefaults.文件保存等一般方式,keychain保存更为安全,而且keychain里保存的信息不会因App被删除而丢失,所以在 重装App后,keychain里的数据还能使用.从ios 3.0开始,跨程序分享keychain变得可行. 如何需要在应用里使用使用keyChain,我们需要导入Security.framework ,key

android 保存 用户名和密码 设置等应用信息优化

1.传统的保存用户名,密码方式 SharedPreferences Editor editor = shareReference.edit(); editor.putString(KEY_NAME,"username_value"); 通过这样的方法,能够基本满足需求,比如有用户名,那么就Editor.putString存放就好. 但是这样的方法有一些弊端: (1)在存放一些集合信息,存储ArrayList就不合适 (2)如果针对用户,新增加了很多熟悉,比如性别,头像等信息,那么需要一

Android简易实战教程--第十六话《SharedPreferences保存用户名和密码》

之前在Android简易实战教程--第七话<在内存中存储用户名和密码> 那里是把用户名和密码保存到了内存中,这一篇把用户名和密码保存至SharedPreferences文件.为了引起误导,声明实际开发中不会用到这两种方式,这里指示提供一种思路和给初学者学习简单的api. 由于内容和之前的基本一样,不做过多的解释.直接上代码: xml文件: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/androi

Android保存用户名和密码

我们不管在开发一个项目或者使用别人的项目,都有用户登录功能,为了让用户的体验效果更好,我们通常会做一个功能,叫做保存用户,这样做的目地就是为了让用户下一次再使用该程序不会重新输入用户名和密码,这里我使用3种方式来存储用户名和密码 1.通过普通 的txt文本存储 2.通过properties属性文件进行存储 3.通过SharedPreferences工具类存储 第一种: /** * 保存用户名和密码的业务方法 * * @param username * @param password * @ret

终于解决“Git Windows客户端保存用户名与密码”的问题

Git - How to use netrc file on windows - Stack Overflow 这就是正确答案,我们已经验证过了,下面详细描述一下解决方法: 1. 在Windows中添加一个HOME环境变量,值为%USERPROFILE%,如下图: 2. 在"开始>运行"中打开%Home%,新建一个名为"_netrc"的文件. 3. 用记事本打开_netrc文件,输入Git服务器名.用户名.密码,并保存.示例如下: machine git.cn

TortoiseSVN客户端重新设置用户名和密码

在第一次使用TortoiseSVN从服务器CheckOut的时候,会要求输入用户名和密码,这时输入框下面有个选项是保存认证信息,如果选了这个选项,那么以后就不用每次都输入一遍用户名密码了. 不过,如果后来在服务器端修改了用户名密码,则再次检出时就会出错,而且这个客户端很弱智,出错之后不会自动跳出用户名密码输入框让人更新,我找了半天也没找到修改这个用户名密码的地方. 最终,找到两种解决办法: 办法一:在TortoiseSVN的设置对话框中,选择"已保存数据",在"认证数据&qu

[转]TortoiseSVN客户端重新设置用户名和密码

在第一次使用TortoiseSVN从服务器CheckOut的时候,会要求输入用户名和密码,这时输入框下面有个选项是保存认证信息,如果选了这个选项,那么以后就不用每次都输入一遍用户名密码了. 不过,如果后来在服务器端修改了用户名密码,则再次检出时就会出错,而且这个客户端很弱智,出错之后不会自动跳出用户名密码输入框让人更新,我找了半天也没找到修改这个用户名密码的地方. 最终,找到两种解决办法: 办法一:在TortoiseSVN的设置对话框中,选择“已保存数据”,在“认证数据”那一行点击“清除”按钮,

TortoiseSVN客户端重新设置用户名和密码[转]

在第一次使用TortoiseSVN从服务器CheckOut的时候,会要求输入用户名和密码,这时输入框下面有个选项是保存认证信息,如果选了这个选项,那么以后就不用每次都输入一遍用户名密码了. 不过,如果后来在服务器端修改了用户名密码,则再次检出时就会出错,而且这个客户端很弱智,出错之后不会自动跳出用户名密码输入框让人更新,我找了半天也没找到修改这个用户名密码的地方. 最终,找到两种解决办法: 办法一:在TortoiseSVN的设置对话框中,选择“已保存数据”,在“认证数据”那一行点击“清除”按钮,