有一些类似的问题,但是没有一个能解决我的问题。
使用Xcode 11.1 MacOS Cataline 10.15
我克隆了此“ active-directory-b2c-ios-swift-native-msal”,并尝试运行以获取错误“无法获取令牌:Error Domain = MSALErrorDomain代码= -50000“(null)” UserInfo = {MSALErrorDescriptionKey =无法启动交互式会话,MSALInternalErrorCodeKey = -42008,MSALCorrelationIDKey = C9207A45-6A7D-416B-90E4-93E08F28A637}” 更改B2C详细信息后,同样的问题变得越来越严重。 请让我知道是什么问题,这是Xcode / OS / MSAL版本的问题还是Code的某些问题?
我尝试使用git repo中的默认配置提及“ active-directory-b2c-ios-swift-native-msal”,还尝试了以下更改,让kTenantName =“ dovervsg.onmicrosoft.com” //您的租户名称 let kClientID =“ xxxxxxxxxxxxxxxxxxxxxxx” //创建应用程序时来自门户的客户端ID let kSignupOrSigninPolicy =“ B2C_1-policy” //您在门户中创建的注册和登录策略 let kEditProfilePolicy =“ b2c_1_edit_profile” //您在门户网站中创建的编辑策略 let kResetPasswordPolicy =“ B2C_1_reset_password” //您在门户网站中创建的重置密码策略 let kGraphURI =“ https://dev-vsg.dovertech.co.in” //这是您的后端API,已将其配置为接受应用程序的令牌 let kScopes:[String] = [“ https://dovervsg.onmicrosoft.com/User.Read”] //这是您配置了后端API所要查找的作用域。 //也尝试过使用这种范围格式,让kScopes:[String] = [“ https://dovervsg.onmicrosoft.com/api/User.Read”] // //这是您已经配置了后端API来查找的范围。
let kTenantName = "dovervsg.onmicrosoft.com" // Your tenant name
let kClientID = "xxxxxxxxxxxxxxxxxxxxxxx" // Your client ID from the portal when you created your application
let kSignupOrSigninPolicy = "B2C_1-policy" // Your signup and sign-in policy you created in the portal
let kEditProfilePolicy = "b2c_1_edit_profile" // Your edit policy you created in the portal
let kResetPasswordPolicy = "B2C_1_reset_password" // Your reset password policy you created in the portal
let kGraphURI = "https://dev-vsg.dovertech.co.in" // This is your backend API that you've configured to accept your app's tokens
let kScopes: [String] = ["https://dovervsg.onmicrosoft.com/User.Read"] // This is a scope that you've configured your backend API to look for.
// tried with this scope format as well,let kScopes: [String] = ["https://dovervsg.onmicrosoft.com/api/User.Read"] // This is a scope that you've configured your backend API to look for
// DO NOT CHANGE - This is the format of OIDC Token and Authorization endpoints for Azure AD B2C.
let kEndpoint = "https://login.microsoftonline.com/tfp/%@/%@"
var application: MSALPublicClientApplication!
var accessToken: String?
@IBOutlet weak var loggingText: UITextView!
@IBOutlet weak var signoutButton: UIButton!
@IBOutlet weak var callGraphApiButton: UIButton!
@IBOutlet weak var editProfileButton: UIButton!
@IBOutlet weak var refreshTokenButton: UIButton!
override func viewDidAppear(_ animated: Bool) {
//super.viewDidLoad()
do {
/**
Initialize a MSALPublicClientApplication with a MSALPublicClientApplicationconfig.
MSALPublicClientApplicationconfig can be initialized with client id,redirect uri and authority.
Redirect uri will be constucted automatically in the form of "msal<your-client-id-here>://auth" if not provided.
The scheme part,i.e. "msal<your-client-id-here>",needs to be registered in the info.plist of the project
*/
let authority = try self.getauthority(forPolicy: self.kSignupOrSigninPolicy)
// Provide configuration for MSALPublicClientApplication
// MSAL will use default redirect uri when you provide nil
let pcaConfig = MSALPublicClientApplicationconfig(clientId: kClientID,redirecturi: nil,authority: authority)
self.application = try MSALPublicClientApplication(configuration: pcaConfig)
} catch {
self.updateLoggingText(text: "Unable to create application \(error)")
}
}
/**
This button will invoke the authorization flow and send the policy specified to the B2C server.
Here we are using the `kSignupOrSignInPolicy` to sign the user in to the app. We will store this
accessToken for subsequent calls.
*/
@IBaction func authorizationButton(_ sender: UIButton) {
do {
/**
authority is a URL indicating a directory that MSAL can use to obtain tokens. In Azure B2C
it is of the form `https://<instance/tfp/<tenant>/<policy>`,where `<instance>` is the
directory host (e.g. https://login.microsoftonline.com),`<tenant>` is a
identifier within the directory itself (e.g. a domain associated to the
tenant,such as contoso.onmicrosoft.com),and `<policy>` is the policy you wish to
use for the current user flow.
*/
let authority = try self.getauthority(forPolicy: self.kSignupOrSigninPolicy)
/**
Acquire a token for a new account using interactive authentication
- scopes: Permissions you want included in the access token received
in the result in the completionBlock. Not all scopes are
gauranteed to be included in the access token returned.
- completionBlock: The completion block that will be called when the authentication
flow completes,or encounters an error.
*/
let webViewParameters = MSALWebviewParameters(parentViewController: self)
let parameters = MSALInteractiveTokenParameters(scopes: kScopes,webviewParameters: webViewParameters)
parameters.promptType = .selectaccount
print( parameters.promptType = .selectaccount)
parameters.authority = authority
debugPrint( parameters.authority = authority)
application.acquireToken(with: parameters) { (result,error) in
guard let result = result else {
self.updateLoggingText(text: "Could not acquire token: \(error ?? "No error informarion" as! Error)")
return
}
self.accessToken = result.accessToken
self.updateLoggingText(text: "access token is \(self.accessToken ?? "Empty")")
self.signoutButton.isEnabled = true
self.callGraphApiButton.isEnabled = true
self.editProfileButton.isEnabled = true
self.refreshTokenButton.isEnabled = true
}
} catch {
self.updateLoggingText(text: "Unable to create authority \(error)")
}
}
@IBaction func editProfile(_ sender: UIButton) {
do {
/**
authority is a URL indicating a directory that MSAL can use to obtain tokens. In Azure B2C
it is of the form `https://<instance/tfp/<tenant>/<policy>`,and `<policy>` is the policy you wish to
use for the current user flow.
*/
let authority = try self.getauthority(forPolicy: self.kEditProfilePolicy)
/**
Acquire a token for a new account using interactive authentication
- scopes: Permissions you want included in the access token received
in the result in the completionBlock. Not all scopes are
gauranteed to be included in the access token returned.
- completionBlock: The completion block that will be called when the authentication
flow completes,or encounters an error.
*/
let thisaccount = try self.getaccountByPolicy(withaccounts: application.allaccounts(),policy: kEditProfilePolicy)
let webViewParameters = MSALWebviewParameters(parentViewController: self)
let parameters = MSALInteractiveTokenParameters(scopes: kScopes,webviewParameters: webViewParameters)
parameters.authority = authority
parameters.account = thisaccount
application.acquireToken(with: parameters) { (result,error) in
if let error = error {
self.updateLoggingText(text: "Could not edit profile: \(error)")
} else {
self.updateLoggingText(text: "Successfully edited profile")
}
}
} catch {
self.updateLoggingText(text: "Unable to construct parameters before calling acquire token \(error)")
}
}
@IBaction func refreshToken(_ sender: UIButton) {
do {
/**
authority is a URL indicating a directory that MSAL can use to obtain tokens. In Azure B2C
it is of the form `https://<instance/tfp/<tenant>/<policy>`,and `<policy>` is the policy you wish to
use for the current user flow.
*/
let authority = try self.getauthority(forPolicy: self.kSignupOrSigninPolicy)
/**
Acquire a token for an existing account silently
- scopes: Permissions you want included in the access token received
in the result in the completionBlock. Not all scopes are
gauranteed to be included in the access token returned.
- account: An account object that we retrieved from the application object before that the
authentication flow will be locked down to.
- completionBlock: The completion block that will be called when the authentication
flow completes,or encounters an error.
*/
guard let thisaccount = try self.getaccountByPolicy(withaccounts: application.allaccounts(),policy: kSignupOrSigninPolicy) else {
self.updateLoggingText(text: "There is no account available!")
return
}
let parameters = MSALSilentTokenParameters(scopes: kScopes,account:thisaccount)
parameters.authority = authority
self.application.acquireTokenSilent(with: parameters) { (result,error) in
if let error = error {
let nsError = error as NSError
// interactionRequired means we need to ask the user to sign-in. This usually happens
// when the user's Refresh Token is expired or if the user has changed their password
// among other possible reasons.
if (nsError.domain == MSALErrorDomain) {
if (nsError.code == MSALError.interactionRequired.rawValue) {
// Notice we supply the account here. This ensures we acquire token for the same account
// as we originally authenticated.
let webviewParameters = MSALWebviewParameters(parentViewController: self)
let parameters = MSALInteractiveTokenParameters(scopes: self.kScopes,webviewParameters: webviewParameters)
parameters.account = thisaccount
self.application.acquireToken(with: parameters) { (result,error) in
guard let result = result else {
self.updateLoggingText(text: "Could not acquire new token: \(error ?? "No error informarion" as! Error)")
return
}
self.accessToken = result.accessToken
self.updateLoggingText(text: "access token is \(self.accessToken ?? "empty")")
}
return
}
}
self.updateLoggingText(text: "Could not acquire token: \(error)")
return
}
guard let result = result else {
self.updateLoggingText(text: "Could not acquire token: No result returned")
return
}
self.accessToken = result.accessToken
self.updateLoggingText(text: "Refreshing token silently")
self.updateLoggingText(text: "Refreshed access token is \(self.accessToken ?? "empty")")
}
} catch {
self.updateLoggingText(text: "Unable to construct parameters before calling acquire token \(error)")
}
}
@IBaction func callApi(_ sender: UIButton) {
guard let accessToken = self.accessToken else {
self.updateLoggingText(text: "Operation failed because could not find an access token!")
return
}
let sessionconfig = URLSessionconfiguration.default
sessionconfig.timeoutIntervalForRequest = 30
let url = URL(string: self.kGraphURI)
var request = URLRequest(url: url!)
request.setvalue("Bearer \(accessToken)",forHTTPHeaderField: "Authorization")
let urlSession = URLSession(configuration: sessionconfig,delegate: self,delegateQueue: OperationQueue.main)
self.updateLoggingText(text: "Calling the API....")
urlSession.dataTask(with: request) { data,response,error in
guard let validData = data else {
self.updateLoggingText(text: "Could not call API: \(error ?? "No error informarion" as! Error)")
return
}
let result = try? JSONSerialization.jsonObject(with: validData,options: [])
guard let validResult = result as? [String: Any] else {
self.updateLoggingText(text: "Nothing returned from API")
return
}
self.updateLoggingText(text: "API response: \(validResult.debugDescription)")
}.resume()
}
@IBaction func signoutButton(_ sender: UIButton) {
do {
/**
Removes all tokens from the cache for this application for the provided account
- account: The account to remove from the cache
*/
let thisaccount = try self.getaccountByPolicy(withaccounts: application.allaccounts(),policy: kSignupOrSigninPolicy)
if let accountToRemove = thisaccount {
try application.remove(accountToRemove)
} else {
self.updateLoggingText(text: "There is no account to signing out!")
}
self.signoutButton.isEnabled = false
self.callGraphApiButton.isEnabled = false
self.editProfileButton.isEnabled = false
self.refreshTokenButton.isEnabled = false
self.updateLoggingText(text: "Signed out")
} catch {
self.updateLoggingText(text: "Received error signing out: \(error)")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(_ animated: Bool) {
if self.accessToken == nil {
signoutButton.isEnabled = false
callGraphApiButton.isEnabled = false
editProfileButton.isEnabled = false
refreshTokenButton.isEnabled = false
}
}
func getaccountByPolicy (withaccounts accounts: [MSALaccount],policy: String) throws -> MSALaccount? {
for account in accounts {
// This is a single account sample,so we only check the suffic part of the object id,// where object id is in the form of <object id>-<policy>.
// For multi-account apps,the whole object id needs to be checked.
if let homeaccountId = account.homeaccountId,let objectId = homeaccountId.objectId {
if objectId.hasSuffix(policy.lowercased()) {
return account
}
}
}
return nil
}
/**
The way B2C knows what actions to perform for the user of the app is through the use of `Authority URL`.
It is of the form `https://<instance/tfp/<tenant>/<policy>`,where `<instance>` is the
directory host (e.g. https://login.microsoftonline.com),`<tenant>` is a
identifier within the directory itself (e.g. a domain associated to the
tenant,and `<policy>` is the policy you wish to
use for the current user flow.
*/
func getauthority(forPolicy policy: String) throws -> MSALB2CAuthority {
guard let authorityURL = URL(string: String(format: self.kEndpoint,self.kTenantName,policy)) else {
throw NSError(domain: "SomeDomain",code: 1,userInfo: ["errorDescription": "Unable to create authority URL!"])
}
return try MSALB2CAuthority(url: authorityURL)
}
func updateLoggingText(text: String) {
DispatchQueue.main.async{
self.loggingText.text = text
}
}
}
运行后出现以上错误