最近一段時(shí)間開發(fā)公司一款MacOS平臺(tái)的App時(shí)需要用到管理員權(quán)限,于是乎上網(wǎng)查詢了MacOS App使用代碼提權(quán)的方式,目前主要有以下幾種:
1.通過ServiceManagement注冊(cè)LaunchdDaemon
這種方法是目前蘋果官方推薦的一種提權(quán)方式,官方也提供了一個(gè)SMJobBless的Demo,但是需要用蘋果開發(fā)者賬號(hào)編譯(我會(huì)在我博客后面的文章單獨(dú)介紹一種不需要開發(fā)者賬號(hào)編譯的方式,也能通過這種方式達(dá)到高權(quán)限的需求,在本文末尾會(huì)提供思路!),而且使用起來很復(fù)雜。帶來的好處是,將高權(quán)限任務(wù)封裝到獨(dú)立的子程序,將按需調(diào)用,不會(huì)讓整個(gè)程序處于高權(quán)限的狀態(tài)會(huì)相對(duì)安全一些,子程序便能輕松實(shí)現(xiàn)開機(jī)自啟、常駐后臺(tái)、高權(quán)限的需求。
我通過研究官方SMJobBless的Demo,發(fā)現(xiàn)其實(shí)是通過launchd工具加載一個(gè)與Daemon程序相關(guān)的標(biāo)準(zhǔn)的plist文件,由于launchd需要高權(quán)限運(yùn)行,所以啟動(dòng)的子程序自然而然也是高權(quán)限運(yùn)行。程序運(yùn)行之后,會(huì)將子程序放到/Library/PrivilegedHelperTools這個(gè)目錄,需要的plist文件會(huì)被放到/Library/LaunchDaemons,這樣launchd加載plist時(shí),會(huì)去啟動(dòng)子程序。
在SMJobBless的Demo中是通過ServiceManagement這個(gè)框架的API來完成提權(quán)操作的,而這框架在10.6就出現(xiàn)了,所以不需要擔(dān)心兼容性的問題。本文在這里不詳細(xì)介紹如何使用相關(guān)API了,只是在這里簡(jiǎn)單說說編譯方法吧!在Demo中的ReadMe.txt中雖然講述的很清楚,但是新版xcode編譯之后的目錄有所不同。(注意:程序雖然編譯成功,但在默認(rèn)的SMJobBlessHelper-Launchd.plist中并沒有RunAtLoad這一屬性,所以launchd不會(huì)啟動(dòng)子程序,只會(huì)將子程序放和plist文件到相關(guān)目錄,如需啟動(dòng)子程序,需在SMJobBlessHelper-Launchd.plist中添加RunAtLoad屬性,Boolean類型,值為YES)
1.在xcode中編譯項(xiàng)目 (Product > Build或者command+b)
2.使用終端進(jìn)入項(xiàng)目根目錄,運(yùn)行以下命令:
./SMJobBlessUtil.py setreq <SMJobBlessApp.app:path> SMJobBlessApp/SMJobBlessApp-Info.plist SMJobBlessHelper/SMJobBlessHelper-Info.plist
<SMJobBlessApp.app:path>是指在xcode左邊的Navigator的product下的編譯的APP的路徑
腳本運(yùn)行成功會(huì)輸出:
SMJobBlessApp/SMJobBlessApp-Info.plist: updated
SMJobBlessHelper/SMJobBlessHelper-Info.plist: updated
3.clean項(xiàng)目(Product > Clean),然后再次編譯(Product > Build)。
4.在項(xiàng)目根目錄下,終端執(zhí)行:
./SMJobBlessUtil.py check <SMJobBlessApp.app:path>
腳本運(yùn)行成功沒有輸出任何東西,說明成功了。
5.運(yùn)行編譯的APP。
這時(shí)會(huì)彈出需要輸入密碼的認(rèn)證提示框,輸入密碼之后,xcode在控制臺(tái)打印Job is available!,App上有顯示The Helper Tool is available!字樣,表示成功運(yùn)行了。
官方Demo:SMJobBless.zip
2.AuthorizationExecuteWithPrivileges函數(shù)
這個(gè)函數(shù)是Security.framework中的一函數(shù),使用很方便,而且還有一個(gè)封裝非常好的庫(kù)STPrivilegedTask,接口和NSTask幾乎一樣。但是AuthorizationExecuteWithPrivileges函數(shù)在MacOS 10.7的時(shí)候就開始被棄用了,在新版的10.13.3中發(fā)現(xiàn)某些時(shí)候會(huì)提權(quán)失敗,所以不推薦使用這種方法,在本文也不做過多介紹!
3.使用AppleScript提權(quán)
AppleScript是蘋果獨(dú)有的腳本語言,通過OC或者Swift都可以調(diào)用AppleScript,在這里提供一個(gè)OC寫的方法:
-(NSDictionary*)doAppleScript:(NSString*)cmd{
cmd=[NSString stringWithFormat:@"do shell script \"%@\" with administrator privileges",cmd];
NSAppleScript *script= [[NSAppleScript alloc] initWithSource:cmd];
NSDictionary *scriptError = nil;
NSAppleEventDescriptor *descriptor = [script executeAndReturnError:&scriptError];
NSMutableDictionary *dicResult=[NSMutableDictionary dictionary];
if(scriptError) {
[dicResult setObject:@NO forKey:@"id"];
[dicResult setObject:[scriptError objectForKey:NSAppleScriptErrorMessage] forKey:@"result"];
} else {
NSAppleEventDescriptor *unicode = [descriptor coerceToDescriptorType:typeUnicodeText];
NSData *data = [unicode data];
NSString *result = [[NSString alloc] initWithCharacters:(unichar*)[data bytes] length:[data length] / sizeof(unichar)];
[dicResult setObject:@YES forKey:@"id"];
[dicResult setObject:result forKey:@"result"];
}
return dicResult;
}
AppleScript方法固然簡(jiǎn)單,但是還有一些缺點(diǎn),比如每次需要管理員權(quán)限時(shí),都需要提示輸入密碼,會(huì)讓用戶感覺你總是在獲取權(quán)限,造成用戶對(duì)你程序的不信任,在執(zhí)行需要等待結(jié)果的命令時(shí),會(huì)造成UI卡住,一直占有線程,所以建議在子線程中運(yùn)行!
4.自創(chuàng)的提權(quán)方法(思路)
提供一個(gè)通過AppleScript啟動(dòng)launchd子程序的思路(我博客后面的文章單獨(dú)做介紹),這樣也可以實(shí)現(xiàn)高權(quán)限,常駐后臺(tái)的需求。
AppleScript可以運(yùn)行shell腳本(方法3提供的OC語言的方法就可以執(zhí)行腳本),而shell腳本可以傳入?yún)?shù),知道這兩點(diǎn),我們就可以在自己項(xiàng)目中建立子程序和需要plist文件,通過AppleScript執(zhí)行管理員權(quán)限運(yùn)行shell腳本,shell腳本把plist文件和子程序移動(dòng)到方法1中的所提到的目錄中,這樣是不是可以達(dá)到一樣的方法呢?感興趣的童鞋可以試試!
本文來源:https://blog.ihitun.com/posts/431360628/
未經(jīng)博主同意不得轉(zhuǎn)載!