반응형
작성 이유 :
Unityframwork에게
accesstoken을 전달해야 하는 issue가 발생하여
서버로 api 통신을 하는 메소드를 만들어야하는 작업이 생겼다.
환경 :
Unityframwork가 objective c로 되어 있어
핸들링도 objective c로 작성해야 한다.
서버에 요청하는 하는 메소드
// argument는
// url : api를 요청할 url 주소
// postData : post 방식으로 사용시 body에 넣어줄 데이터
+ (NSData *)request:(NSString *)method url:(NSString *)url postData:(NSData *)postData{=
// result: completionHandler 핸들러의 결과 값을 저장할 변수
__block NSData * result = nil;
// NSMutableURLRequest : 서버에 api 요청하기 위한 scheme
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]init];
// url string 설정
[request setURL:[NSURL URLWithString:url]];
// start 헤더 세팅 ~
NSString *authValue = [NSString stringWithFormat: @"Bearer %@",accessToken];
[request setValue:authValue forHTTPHeaderField:@"Authorization"];
NSString *postLength = [NSString stringWithFormat:@"application/json"];
[request setValue:postLength forHTTPHeaderField:@"accept"];
// ~ 헤더 세팅 end
// 만약 get 방식이라면
if([method isEqualToString:@"GET"])
{
[request setHTTPMethod:@"GET"];
}else{
// 만약 post 방식이라면
[request setHTTPMethod:@"POST"];
[request setHTTPBody:postData];
}
// 서버의 응답을 비동기로 받기 위해 semaphore 시작
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
// NSURLSession : 네트위크 데이터 전송과 관련된 것을 조정하는 객체
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
// dataTaskWithRequest : 지정한 url 요청 객체를 기준으로 내용을 검색하는 작업을 만든다.
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
if (error) {
NSLog(@"error = %@", error);
result = nil;
// error발생으로 semaphore 종료
dispatch_semaphore_signal(semaphore);
return;
}
// network statusCode parsing
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
// 200 ~ 500 때 조건일 경우 서버 데이터를 result 변수에 넣기
if (statusCode >= 200 && statusCode < 500) {
result = data;
}
// 서버에 응답을 받았기 때문에 semaphore 종료
dispatch_semaphore_signal(semaphore);
return;
}]resume];
// 위 작업을 끝날때 까지 대기
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return result;
}
accesstoken을 요청하는 메소드
// 공통의 prefix url define
#define URL @"https://test.test.test"
// 서버에 요청 필요한 argument를 상황에 맞게 만들면 된다.
// 나같은 경우에는 appkey, userid가 필요
(NSDictionary *)requestAccessToken:(NSString *)appKey userid:(NSString*)userId{
// key value 형식인 NSMutableDictionary에 데이터를 담아 return할 예정
NSMutableDictionary *accessTokenStatus = [[NSMutableDictionary alloc] init];
NSString *url = [NSString stringWithFormat:@"%@/client/auth/init",URL];
// post method body
NSString *postParams = [NSString stringWithFormat:@"appKey=%@&userId=%@",appKey,userId];
// dataUsingEncoding: 옵션 형태에 맞는 NSData로 변환
NSData *postData = [postParams dataUsingEncoding:NSUTF8StringEncoding];
// 예외 처리를 위해 @try ~ catch 구문 사용
@try{
// 위에 작성한 request 메소들 서버에 accesstoken 발급 요청
NSData *result = [self request:@"POST" url:url postData:postData];
// 서버에 응답 받은 데이터를 json 형태로 변환
id json = [NSJSONSerialization JSONObjectWithData:result options:0 error:nil];
// 조건에 따라 분기
if([json objectForKey:@"error"]){
[accessTokenStatus setObject:@NO forKey:@"status"];
[accessTokenStatus setObject:[[json objectForKey:@"error"] objectForKey:@"code"] forKey:@"accessToken"];
[accessTokenStatus setObject:[[[json objectForKey:@"error"] objectForKey:@"desc"] objectAtIndex:0] forKey:@"errorMsg"];
return accessTokenStatus;
}
// 전역으로 선언한 accessToken, refreshToken 변수에 서버에 응답 받은 토큰을 저장
accessToken = [json objectForKey:@"accessToken"];
refreshToken = [json objectForKey:@"refreshToken"];
[accessTokenStatus setObject:@YES forKey:@"status"];
return accessTokenStatus;
} @catch (NSException *exception){
[accessTokenStatus setObject:@NO forKey:@"status"];
[accessTokenStatus setObject:@"NETWORK_ERROR" forKey:@"accessToken"];
[accessTokenStatus setObject:@"네트워크 환경을 확인해주세요" forKey:@"errorMsg"];
return accessTokenStatus;
}
};
jwt 유효성 확인하는 메서드
(BOOL)validationAccessToken{
// accessToken 전역변수에 저장여부를 확인
// 저장이 안되어 있다면 유효성 확인이 불필요 하기 때문
if(accessToken == nil){
return NO;
}
NSString *jwtToken = accessToken;
// 유효성을 expire 시간을 기준으로 하기 때문에
// 현재 시간을 unix 형태로 가져옴
int currentTime = [[NSDate date] timeIntervalSince1970];
// "."을 기준으로 string을 나누기
NSArray *components = [jwtToken componentsSeparatedByString:@"."];
// jwt .이 2개가 있기에 총 3개의 인덱스로 나눠지고
// 기중 2번째 배열에 data 정보 즉 expire time이 있기에 그정보를 payloadBase64Url변수에 넣어준다.
NSString *payloadBase64Url = components[1];
NSString *payloadBase64 = [[payloadBase64Url stringByReplacingOccurrencesOfString:@"-" withString:@"+"] stringByReplacingOccurrencesOfString:@"_" withString:@"/"];
// objective는 4bit 단위로 정확히 떨어지지 않으면 encode, decode가 불가능하다
// 그래서 만약 4bit 단위로 맞지 않으면 임의 "=" 패딩 값을 넣어 맞춰줘서 decode 해야한다.
while ([payloadBase64 length] % 4 != 0) {
payloadBase64 = [payloadBase64 stringByAppendingString:@"="];
};
// 4bit 단위로 맞춰준 jwt의 data값을 decoding 해준다.
NSData *payloadData = [[NSData alloc] initWithBase64EncodedString:payloadBase64 options:0];
// json 형태로 변경해주고
id json = [NSJSONSerialization JSONObjectWithData:payloadData options:0 error:nil];
// expire time value를 비교 해준다.
if([[json objectForKey:@"exp"] intValue] > currentTime){
return YES;
}else{
return NO;
}
}
728x90
'모바일 APP > Swift' 카테고리의 다른 글
Objective C Enum을 -> Swift에서 사용하기 (0) | 2023.06.26 |
---|---|
S3 쉘스크립트 만들기 (1) | 2023.04.05 |
Xcode 구조 (0) | 2021.05.31 |
IOS 개발 조건 (0) | 2021.05.31 |