AppAuth в приложении IOS, проблема при обновлении кода авторизации/оповещения кратко отображается, а затем уходит

Я использую модуль AppAuth для обработки входа пользователя в Azure в своем приложении. Я следовал этому примеру: https://github.com/openid/AppAuth-iOS/tree/master/Examples, который отлично работает, пока не истечет срок действия моего кода аутентификации. Он работает нормально для 1-го соединения и все время, пока код проверки подлинности все еще действителен. По истечении срока действия я ненадолго вижу предупреждение «Войти», а затем оно исчезает, и я получаю сообщение об ошибке: «Попытка загрузить представление контроллера представления во время его освобождения не разрешена и может привести к неопределенному поведению ()» . (Он снова работает нормально, если я удалю приложение и переустановлю его.)

Я прочитал, что я должен «убедиться, что существует строгая ссылка на экземпляр SFAuthenticationSession, когда сеанс выполняется». И я думаю, что дело в этом: viewController, из которого я выполняю вход, имеет свою личную переменную 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
}

Любое предложение приветствуется :)


person Emilie BELLIER    schedule 22.04.2020    source источник
comment
Кажется, что SFAuthenticationViewController имеет счетчик сохранения 2 после исчезновения предупреждения, когда он должен быть 1. Как если бы это было removeFromSuperview() ?   -  person Emilie BELLIER    schedule 27.04.2020
comment
Никто никогда не сталкивался с этой проблемой?   -  person Emilie BELLIER    schedule 19.05.2020
comment
У меня также есть эта проблема с ReactNative Wrspper для AppAuth, но, к сожалению, пока нет решения: github.com/FormidableLabs/react-native-app-auth/issues/525   -  person the_smart_home_maker    schedule 07.07.2020


Ответы (1)


Я смог решить проблему, просто заменив макрос в info.plist для схемы URL-адреса фактической строкой идентификатора пакета.

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

person Stuart Buchbinder    schedule 27.04.2021