首页 > 解决方案 > IOS App中的AppAuth,更新授权代码时发出问题/警报短暂显示然后消失

问题描述

我正在使用 AppAuth pod 在我的应用程序中使用 Azure 处理用户登录。我遵循了这个示例:https://github.com/openid/AppAuth-iOS/tree/master/Examples在我的身份验证代码过期之前可以正常工作。它适用于第一次连接,并且在 authenticationCode 仍然有效的情况下一直有效。一旦它过期,我会短暂地看到“登录”的警报,然后它消失了,我收到错误:“不允许在解除分配时尝试加载视图控制器的视图,并且可能导致未定义的行为 ()” . (如果我删除该应用程序并重新安装它,它会再次正常工作。)

我读到我应该“确保在会话进行时有对 SFAuthenticationSession 实例的强引用。”。我认为情况就是这样:我登录的 viewController 有它的私有 var authState。(见下面的代码)有人解决了这个问题吗?

import UIKit
import AppAuth
import AuthenticationServices

var isLoginViewOn: Bool = false
var isConnectionBtnPressed: Bool = false

class ContainerController: UIViewController {


// MARKS : Properties

private var authState: OIDAuthState?
var token: String?

var menuController: MenuController!   
var homeController: HomeController!
var panView: UIView!
var isExpanded = false

var isLoginOut: Bool = false

let loginView: UIImageView = {
    let v = UIImageView()
    v.image = UIImage(named: "")
    v.contentMode = .scaleAspectFit
    return v
}()

let connexionButton: UIButton = {
    let b = UIButton(frame: CGRect(x: 100, y: 100, width: 100, height: 50))
    return b
}()

let logoutBtn: UIButton = {
    let b = UIButton(frame: CGRect(x: 100, y: 100, width: 100, height: 50))
    b.setTitle("déconnexion", for: .normal)
    return b
}()


override func viewDidLoad() {
    super.viewDidLoad()
     chekToken()   
}



override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    if isLoginViewOn == true {
        if isConnectionBtnPressed == false {
            self.connexionButton.sendActions(for: .touchUpInside)
            isLoginViewOn = false
        } 

    }
}
    override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    view.layoutIfNeeded()
    view.layoutSubviews()
}

/////////////////////////////////////////////////////////////////////////////
///                                 SET UP                               ////
/////////////////////////////////////////////////////////////////////////////


func setupLoginView() {
    print("setup loginView")
    isLoginViewOn = true
    view.addSubview(loginView)
    view.addSubview(connexionButton)

    loginView.translatesAutoresizingMaskIntoConstraints = false
    connexionButton.translatesAutoresizingMaskIntoConstraints = false

    [
        loginView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
        loginView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        loginView.widthAnchor.constraint(equalToConstant: 250),
        loginView.heightAnchor.constraint(equalToConstant: 128),


        connexionButton.bottomAnchor.constraint(equalTo: loginView.topAnchor, constant: -50),
        connexionButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        connexionButton.widthAnchor.constraint(equalToConstant: 200),
        connexionButton.heightAnchor.constraint(equalToConstant: 50),

        ].forEach{$0.isActive = true }

    connexionButton.addTarget(self, action: #selector(buttonAction(_:)), for: .touchUpInside)

    if isConnectionBtnPressed == false {
        self.connexionButton.sendActions(for: .touchUpInside)
    }
}


func setupHomeController() {
    homeController = HomeController()
    homeController.delegate = self 
    addControllerAsChild(forController: homeController)
    setupPanView(forController: homeController)
}

}

/// 登录 ////

extension ContainerController {


@objc func buttonAction(_ sender: UIButton){
    self.login()
    isConnectionBtnPressed = true
}

func checkToken() {
        guard let data = UserDefaults.standard.object(forKey: kAppAuthExampleAuthStateKey) as? Data else {
            setupLoginView()
            return
        }

        do {
            let authState = try NSKeyedUnarchiver.unarchivedObject(ofClass: OIDAuthState.self, from: data)
            self.setAuthState(authState)
            self.getUserInfo()
        } catch { print("catch loadState: \(error)") }
}


func login() {
    print("Got configuration: \(config)")
       if let clientId = kClientID {
           self.doAuthWithAutoCodeExchange(configuration: config, clientID: clientId, clientSecret: nil)
       }

   }


        func doAuthWithAutoCodeExchange(configuration: OIDServiceConfiguration, clientID: String, clientSecret: String?) {
            guard let redirectURI = URL(string: kRedirectURI) else {
                print("Error creating URL for : \(kRedirectURI)")
                return
            }

            guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
                print("Error accessing AppDelegate")
                return
            }

            // builds authentication request

            let request = OIDAuthorizationRequest(configuration: configuration,
                                                  clientId: clientID,
                                                  clientSecret: clientSecret,
                                                  scopes: [OIDScopeOpenID, OIDScopeProfile, "--kclientID--", "offline_access"],
                                                  redirectURL: redirectURI,
                                                  responseType: OIDResponseTypeCode,
                                                  additionalParameters: ["p": "b2c_1_my_app_sign_in_up"])


            // performs authentication request
            print("Initiating authorization request with scope: \(request.scope ?? "DEFAULT_SCOPE")")

            appDelegate.currentAuthorizationFlow = OIDAuthState.authState(byPresenting: request, presenting: self) { authState, error in
                if let authState = authState {
                   self.setAuthState(authState)
                   print("Got authorization tokens. Access token")
                   self.getUserInfo()

                } else {
                    self.setAuthState(nil)
                    print("Authorization error: \(error?.localizedDescription ?? "DEFAULT_ERROR")")

                }
            }
        }

 func getUserInfo() {
     let currentAccessToken: String? = self.authState?.lastTokenResponse?.accessToken
       self.authState?.performAction() { (accessToken, idToken, error) in
           if error != nil  {
            CoreDataHelper().deleteIDToken("idToken")
            AuthenticationService().login()
               print("Error fetching fresh tokens: \(error?.localizedDescription ?? "ERROR")")
               return
           }

           guard let accessToken = accessToken else {
               print("Error getting accessToken")
               return
           }

           if currentAccessToken != accessToken {
            print("Access token was refreshed automatically ")
             self.token = currentAccessToken
           } else {
            print("Access token was fresh and not updated ")
             self.token = accessToken
           }

        self.loginView.removeFromSuperview() 
        self.setupHomeController()
       }
 }


func saveState() {
    var data: Data? = nil

    if let authState = self.authState {
        do {
            data = try NSKeyedArchiver.archivedData(withRootObject: authState, requiringSecureCoding: false)

        } catch { print("catch saveState: \(error)") }

    }
    UserDefaults.standard.set(data, forKey: kAppAuthExampleAuthStateKey)
    UserDefaults.standard.synchronize()
}

func setAuthState(_ authState: OIDAuthState?) {
    if (self.authState == authState) {
        return;
    }
    self.authState = authState;
    self.authState?.stateChangeDelegate = self;
    self.saveState()
}


}
extension ContainerController: ASWebAuthenticationPresentationContextProviding {
func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
    return view.window!
}

}

在 AppDelegate 中,我把它放在了顶部:

let kClientID: String? = "my client id";
let kRedirectURI: String = "myapp.test.authent://oauth/redirect";
let kAppAuthExampleAuthStateKey: String = "authState";

let authorizationEndpoint = URL(string: "https://login.microsoftonline.com/myapp.onmicrosoft.com/oauth2/v2.0/authorize?p=b2c_1_myaapp_sign_in_up")!
let tokenEndpoint = URL(string: "https://login.microsoftonline.com/myapp.onmicrosoft.com/oauth2/v2.0/token?p=b2c_1_myaapp_sign_in_up")!
let config = OIDServiceConfiguration(authorizationEndpoint: authorizationEndpoint,
                                            tokenEndpoint: tokenEndpoint)

在 AppDelegate 类中:

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        // Sends the URL to the current authorization flow (if any) which will
        // process it if it relates to an authorization response.
        if let authorizationFlow = self.currentAuthorizationFlow, authorizationFlow.resumeExternalUserAgentFlow(with: url) {
            self.currentAuthorizationFlow = nil
            return true
        }

    return false
}

欢迎任何建议:)

标签: iosauthenticationappauth

解决方案


只需将 URL Scheme 的 info.plist 中的宏替换为包标识符的实际字符串,我就能够解决此问题。

https://github.com/openid/AppAuth-iOS/issues/545


推荐阅读