Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Şunlar için geçerlidir: İş gücü kiracıları
Dış kiracılar (daha fazla bilgi edinin)
Bu, Microsoft Entra Id kullanarak kullanıcılarda oturum açma konusunda size yol gösteren öğretici serisinin üçüncü öğreticisidir.
Başlamadan önce, kiracı türünü seçmek için bu sayfanın üst kısmındaki Kiracı türü seçici'i kullanın. Microsoft Entra ID, iş gücü ve dışolmak üzere iki kiracı yapılandırması sağlar. İş gücü kiracı yapılandırması çalışanlarınıza, iç uygulamalarınıza ve diğer kuruluş kaynaklarınıza yöneliktir. Dış kiracı, müşteriye yönelik uygulamalarınız içindir.
Bu öğreticide:
- Kullanıcı oturum aç.
- Kullanıcı oturumunu kapatın.
- Uygulamanızın kullanıcı arabirimini oluşturma
Önkoşullar
- Öğreticisi: iOS (Swift) uygulamanızı kimlik doğrulaması için hazırlama
Kullanıcı oturum aç
iOS için Microsoft Kimlik Doğrulama Kitaplığı'nı (MSAL) kullanarak kullanıcıların oturum açması için iki ana seçeneğiniz vardır: belirteçleri etkileşimli olarak veya sessizce almak.
Kullanıcı etkileşimli olarak oturum açmak için aşağıdaki kodu kullanın:
func acquireTokenInteractively() { guard let applicationContext = self.applicationContext else { return } guard let webViewParameters = self.webViewParameters else { return } // #1 let parameters = MSALInteractiveTokenParameters(scopes: kScopes, webviewParameters: webViewParameters) parameters.promptType = .selectAccount // #2 applicationContext.acquireToken(with: parameters) { (result, error) in // #3 if let error = error { self.updateLogging(text: "Could not acquire token: \(error)") return } guard let result = result else { self.updateLogging(text: "Could not acquire token: No result returned") return } // #4 self.accessToken = result.accessToken self.updateLogging(text: "Access token is \(self.accessToken)") self.updateCurrentAccount(account: result.account) self.getContentWithToken() } }
promptType
MSALInteractiveTokenParameters
özelliği, kimlik doğrulaması ve onay istemi davranışını yapılandırmaktadır. Aşağıdaki değerler desteklenir:-
.promptIfNecessary
(varsayılan ayar) - Kullanıcıdan yalnızca gerekirse istenir. SSO deneyimi, webview'de çerezlerin bulunmasına ve hesap türüne göre belirlenir. Birden çok kullanıcı oturum açtıysa hesap seçimi deneyimi sunulur. Bu,varsayılan davranıştır. -
.selectAccount
- Kullanıcı belirtilmezse, kimlik doğrulama web görünümü kullanıcının seçebilmek için şu anda oturum açmış olan hesapların listesini sunar. -
.login
- Kullanıcının web görünümünde kimlik doğrulamasını gerektirir. Bu değeri belirtirseniz aynı anda yalnızca bir hesap oturum açabilir. -
.consent
- Kullanıcının istek için geçerli kapsam kümesini onaylamasını gerektirir.
-
Kullanıcının sessizce oturum açması için aşağıdaki kodu kullanın:
func acquireTokenSilently(_ account : MSALAccount!) { guard let applicationContext = self.applicationContext else { return } /** Acquire a token for an existing account silently - forScopes: Permissions you want included in the access token received in the result in the completionBlock. Not all scopes are guaranteed 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. */ let parameters = MSALSilentTokenParameters(scopes: kScopes, account: account) applicationContext.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) { DispatchQueue.main.async { self.acquireTokenInteractively() } return } } self.updateLogging(text: "Could not acquire token silently: \(error)") return } guard let result = result else { self.updateLogging(text: "Could not acquire token: No result returned") return } self.accessToken = result.accessToken self.updateLogging(text: "Refreshed Access token is \(self.accessToken)") self.updateSignOutButton(enabled: true) self.getContentWithToken() } }
acquireTokenSilently
yöntemi, mevcut bir MSAL hesabı için sessizce erişim belirteci almayı dener. Belirtilen kapsamlara sahip belirteci istemek içinapplicationContext
kullanır. Bir hata oluşursa, kullanıcı etkileşiminin gerekli olup olmadığını denetler ve gerekliyse etkileşimli bir belirteç alımı başlatır. Başarılı olduğunda erişim belirtecini günceller, sonucu günlüğe kaydeder, oturum kapatma düğmesini etkinleştirir ve belirteci kullanarak içeriği alır.
Oturum açma geri çağırmasını işleme (yalnızca iOS)
AppDelegate.swift dosyasını açın. Oturum açmadan sonra geri çağırmayı işlemek için MSALPublicClientApplication.handleMSALResponse
sınıfına aşağıdaki gibi appDelegate
ekleyin:
// Inside AppDelegate...
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
return MSALPublicClientApplication.handleMSALResponse(url, sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String)
}
Xcode 11kullanıyorsanız bunun yerine SceneDelegate.swift MSAL geri çağırması yerleştirmelisiniz. Eski iOS ile uyumluluk için hem UISceneDelegate hem de UIApplicationDelegate'i destekliyorsanız, MSAL geri çağırmanın her iki dosyaya da yerleştirilmesi gerekir.
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let urlContext = URLContexts.first else {
return
}
let url = urlContext.url
let sourceApp = urlContext.options.sourceApplication
MSALPublicClientApplication.handleMSALResponse(url, sourceApplication: sourceApp)
}
Oturumu kapatan kullanıcı
Önemli
MSAL ile oturum kapatıldığında kullanıcıyla ilgili tüm bilinen bilgiler uygulamadan kaldırılır ve cihaz yapılandırmasına izin verildiğinde cihazdaki etkin kullanıcı oturumu da sonlandırılır. İsterseniz kullanıcının tarayıcıdan oturumunu kapatabilirsiniz.
Oturum kapatma özelliği eklemek için aşağıdaki kodu ViewController
sınıfına ekleyin.
@objc func signOut(_ sender: AnyObject) {
guard let applicationContext = self.applicationContext else { return }
guard let account = self.currentAccount else { return }
do {
/**
Removes all tokens from the cache for this application for the provided account
- account: The account to remove from the cache
*/
let signoutParameters = MSALSignoutParameters(webviewParameters: self.webViewParameters!)
signoutParameters.signoutFromBrowser = false // set this to true if you also want to signout from browser or webview
applicationContext.signout(with: account, signoutParameters: signoutParameters, completionBlock: {(success, error) in
if let error = error {
self.updateLogging(text: "Couldn't sign out account with error: \(error)")
return
}
self.updateLogging(text: "Sign out completed successfully")
self.accessToken = ""
self.updateCurrentAccount(account: nil)
})
}
}
Uygulamanızın kullanıcı arabirimini oluşturma
Şimdi ViewController
sınıfına aşağıdaki kodu ekleyerek Microsoft Graph API'sini çağırmak için bir düğme, oturumu kapatmak için başka bir düğme ve bazı çıktıları görmek için bir metin görünümü içeren bir kullanıcı arabirimi oluşturun:
iOS kullanıcı arabirimi
var loggingText: UITextView!
var signOutButton: UIButton!
var callGraphButton: UIButton!
var usernameLabel: UILabel!
func initUI() {
usernameLabel = UILabel()
usernameLabel.translatesAutoresizingMaskIntoConstraints = false
usernameLabel.text = ""
usernameLabel.textColor = .darkGray
usernameLabel.textAlignment = .right
self.view.addSubview(usernameLabel)
usernameLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 50.0).isActive = true
usernameLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -10.0).isActive = true
usernameLabel.widthAnchor.constraint(equalToConstant: 300.0).isActive = true
usernameLabel.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
// Add call Graph button
callGraphButton = UIButton()
callGraphButton.translatesAutoresizingMaskIntoConstraints = false
callGraphButton.setTitle("Call Microsoft Graph API", for: .normal)
callGraphButton.setTitleColor(.blue, for: .normal)
callGraphButton.addTarget(self, action: #selector(callGraphAPI(_:)), for: .touchUpInside)
self.view.addSubview(callGraphButton)
callGraphButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
callGraphButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 120.0).isActive = true
callGraphButton.widthAnchor.constraint(equalToConstant: 300.0).isActive = true
callGraphButton.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
// Add sign out button
signOutButton = UIButton()
signOutButton.translatesAutoresizingMaskIntoConstraints = false
signOutButton.setTitle("Sign Out", for: .normal)
signOutButton.setTitleColor(.blue, for: .normal)
signOutButton.setTitleColor(.gray, for: .disabled)
signOutButton.addTarget(self, action: #selector(signOut(_:)), for: .touchUpInside)
self.view.addSubview(signOutButton)
signOutButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
signOutButton.topAnchor.constraint(equalTo: callGraphButton.bottomAnchor, constant: 10.0).isActive = true
signOutButton.widthAnchor.constraint(equalToConstant: 150.0).isActive = true
signOutButton.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
let deviceModeButton = UIButton()
deviceModeButton.translatesAutoresizingMaskIntoConstraints = false
deviceModeButton.setTitle("Get device info", for: .normal);
deviceModeButton.setTitleColor(.blue, for: .normal);
deviceModeButton.addTarget(self, action: #selector(getDeviceMode(_:)), for: .touchUpInside)
self.view.addSubview(deviceModeButton)
deviceModeButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
deviceModeButton.topAnchor.constraint(equalTo: signOutButton.bottomAnchor, constant: 10.0).isActive = true
deviceModeButton.widthAnchor.constraint(equalToConstant: 150.0).isActive = true
deviceModeButton.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
// Add logging textfield
loggingText = UITextView()
loggingText.isUserInteractionEnabled = false
loggingText.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(loggingText)
loggingText.topAnchor.constraint(equalTo: deviceModeButton.bottomAnchor, constant: 10.0).isActive = true
loggingText.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 10.0).isActive = true
loggingText.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: -10.0).isActive = true
loggingText.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 10.0).isActive = true
}
func platformViewDidLoadSetup() {
NotificationCenter.default.addObserver(self,
selector: #selector(appCameToForeGround(notification:)),
name: UIApplication.willEnterForegroundNotification,
object: nil)
}
@objc func appCameToForeGround(notification: Notification) {
self.loadCurrentAccount()
}
macOS kullanıcı arabirimi
var callGraphButton: NSButton!
var loggingText: NSTextView!
var signOutButton: NSButton!
var usernameLabel: NSTextField!
func initUI() {
usernameLabel = NSTextField()
usernameLabel.translatesAutoresizingMaskIntoConstraints = false
usernameLabel.stringValue = ""
usernameLabel.isEditable = false
usernameLabel.isBezeled = false
self.view.addSubview(usernameLabel)
usernameLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 30.0).isActive = true
usernameLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -10.0).isActive = true
// Add call Graph button
callGraphButton = NSButton()
callGraphButton.translatesAutoresizingMaskIntoConstraints = false
callGraphButton.title = "Call Microsoft Graph API"
callGraphButton.target = self
callGraphButton.action = #selector(callGraphAPI(_:))
callGraphButton.bezelStyle = .rounded
self.view.addSubview(callGraphButton)
callGraphButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
callGraphButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 50.0).isActive = true
callGraphButton.heightAnchor.constraint(equalToConstant: 34.0).isActive = true
// Add sign out button
signOutButton = NSButton()
signOutButton.translatesAutoresizingMaskIntoConstraints = false
signOutButton.title = "Sign Out"
signOutButton.target = self
signOutButton.action = #selector(signOut(_:))
signOutButton.bezelStyle = .texturedRounded
self.view.addSubview(signOutButton)
signOutButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
signOutButton.topAnchor.constraint(equalTo: callGraphButton.bottomAnchor, constant: 10.0).isActive = true
signOutButton.heightAnchor.constraint(equalToConstant: 34.0).isActive = true
signOutButton.isEnabled = false
// Add logging textfield
loggingText = NSTextView()
loggingText.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(loggingText)
loggingText.topAnchor.constraint(equalTo: signOutButton.bottomAnchor, constant: 10.0).isActive = true
loggingText.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 10.0).isActive = true
loggingText.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: -10.0).isActive = true
loggingText.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -10.0).isActive = true
loggingText.widthAnchor.constraint(equalToConstant: 500.0).isActive = true
loggingText.heightAnchor.constraint(equalToConstant: 300.0).isActive = true
}
func platformViewDidLoadSetup() {}
Ardından, ViewController
sınıfının içinde de viewDidLoad()
yöntemini şununla değiştirin:
override func viewDidLoad() {
super.viewDidLoad()
initUI()
do {
try self.initMSAL()
} catch let error {
self.updateLogging(text: "Unable to create Application Context \(error)")
}
self.loadCurrentAccount()
self.platformViewDidLoadSetup()
}
Sonraki adımlar
Bu, Microsoft Entra Id kullanarak kullanıcılarda oturum açma konusunda size yol gösteren öğretici serisinin üçüncü öğreticisidir.
Başlamadan önce, kiracı türünü seçmek için bu sayfanın üst kısmındaki Kiracı türü seçici'i kullanın. Microsoft Entra ID, iş gücü ve dışolmak üzere iki kiracı yapılandırması sağlar. İş gücü kiracı yapılandırması çalışanlarınıza, iç uygulamalarınıza ve diğer kuruluş kaynaklarınıza yöneliktir. Dış kiracı, müşteriye yönelik uygulamalarınız içindir.
Bu öğreticide:
- Kullanıcı oturum aç.
- Kullanıcı oturumunu kapatın.
Önkoşullar
- Öğreticisi: iOS (Swift) uygulamanızı kimlik doğrulaması için hazırlama
Kullanıcı oturum aç
iOS için Microsoft Kimlik Doğrulama Kitaplığı'nı (MSAL) kullanarak kullanıcıların oturum açması için iki ana seçeneğiniz vardır: belirteçleri etkileşimli olarak veya sessizce almak.
Kullanıcı etkileşimli olarak oturum açmak için aşağıdaki kodu kullanın:
acquireTokenInteractively() { guard let applicationContext = self.applicationContext else { return } guard let webViewParameters = self.webViewParameters else { return } updateLogging(text: "Acquiring token interactively...") let parameters = MSALInteractiveTokenParameters(scopes: Configuration.kScopes, webviewParameters: webViewParameters) parameters.promptType = .selectAccount applicationContext.acquireToken(with: parameters) { (result, error) in if let error = error { self.updateLogging(text: "Could not acquire token: \(error)") return } guard let result = result else { self.updateLogging(text: "Could not acquire token: No result returned") return } self.accessToken = result.accessToken self.updateLogging(text: "Access token is \(self.accessToken)") self.updateCurrentAccount(account: result.account) } }
Kod önce uygulama bağlamı ve web görünümü parametrelerinin kullanılabilir olup olmadığını denetler. Ardından, belirtecin etkileşimli olarak edinildiğini göstermek için günlüğü günceller. Ardından, kapsamları ve web görünümü parametrelerini belirterek etkileşimli belirteç alımı için parametreler ayarlar. Ayrıca, bir hesap seçmek için istem türünü ayarlar.
Daha sonra, tanımlanan parametrelerle uygulama bağlamında
acquireToken
yöntemini çağırır. Tamamlama işleyicisinde hataları denetler. Bir hata ile karşılaşıldığında, hata mesajını günlüğe kaydeder. Başarılı olursa, sonuçtan erişim belirtecini alır, kayıtlarını belirteçle günceller ve geçerli hesabı günceller.Uygulamanız bir erişim belirteci aldıktan sonra geçerli hesapla ilişkili talepleri alabilirsiniz. Bunu yapmak için aşağıdaki kod parçacığını kullanın:
let claims = result.account.accountClaims let preferredUsername = claims?["preferred_username"] as? String
Kod,
accountClaims
nesnesininresult.account
özelliğine erişerek hesaptan talepleri okur. Daha sonra talep sözlüğünden "preferred_username" talebi değerini alır vepreferredUsername
değişkenine atar.Kullanıcının sessizce oturum açması için aşağıdaki kodu kullanın:
func acquireTokenSilently() { self.loadCurrentAccount { (account) in guard let currentAccount = account else { self.updateLogging(text: "No token found, try to acquire a token interactively first") return } self.acquireTokenSilently(currentAccount) } }
Kod, belirteçleri sessizce alma işlemini başlatır. Geçerli hesabı yüklemeyi önce dener. Geçerli bir hesap bulunursa, bu hesabı kullanarak jetonu sessizce elde etmeye devam eder. Geçerli bir hesap bulunamazsa, belirteç bulunamadığını belirtmek için günlük kaydını günceller ve önce etkileşimli olarak bir belirteç edinmeyi denemeyi önerir.
Yukarıdaki kodda
loadCurrentAccount
veacquireTokenSilently
iki işlevi çağırıyoruz.loadCurrentAccount
işlevi aşağıdaki koda sahip olmalıdır:func loadCurrentAccount(completion: AccountCompletion? = nil) { guard let applicationContext = self.applicationContext else { return } let msalParameters = MSALParameters() msalParameters.completionBlockQueue = DispatchQueue.main // Note that this sample showcases an app that signs in a single account at a time applicationContext.getCurrentAccount(with: msalParameters, completionBlock: { (currentAccount, previousAccount, error) in if let error = error { self.updateLogging(text: "Couldn't query current account with error: \(error)") return } if let currentAccount = currentAccount { self.updateCurrentAccount(account: currentAccount) self.acquireTokenSilently(currentAccount) if let completion = completion { completion(self.currentAccount) } return } // If testing with Microsoft's shared device mode, see the account that has been signed out from another app. More details here: // https://docs.microsoft.com/azure/active-directory/develop/msal-ios-shared-devices if let previousAccount = previousAccount { self.updateLogging(text: "The account with username \(String(describing: previousAccount.username)) has been signed out.") } else { self.updateLogging(text: "") } self.accessToken = "" self.updateCurrentAccount(account: nil) if let completion = completion { completion(nil) } }) }
Kod, iOS'ta geçerli hesabı yüklemek için MSAL kullanır. Hataları kontrol eder ve günlüğü buna göre günceller. Geçerli bir hesap bulunursa, onu günceller ve belirteçleri sessizce almaya çalışır. Önceki bir hesap varsa oturum kapatmayı günlüğe kaydeder. Hesap bulunamazsa erişim belirtecini temizler. Son olarak, eğer bir tamamlama bloğu sağlanmışsa, onu gerçekleştirir.
acquireTokenSilently
işlevi aşağıdaki kodu içermelidir:func acquireTokenSilently(_ account : MSALAccount) { guard let applicationContext = self.applicationContext else { return } /** Acquire a token for an existing account silently - forScopes: Permissions you want included in the access token received in the result in the completionBlock. Not all scopes are guaranteed 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. */ updateLogging(text: "Acquiring token silently...") let parameters = MSALSilentTokenParameters(scopes: Configuration.kScopes, account: account) applicationContext.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) { DispatchQueue.main.async { self.acquireTokenInteractively() } return } } self.updateLogging(text: "Could not acquire token silently: \(error)") return } guard let result = result else { self.updateLogging(text: "Could not acquire token: No result returned") return } self.accessToken = result.accessToken self.updateLogging(text: "Refreshed Access token is \(self.accessToken)") self.updateSignOutButton(enabled: true) } }
Bu işlev, mevcut bir hesap için gizlice bir belirteç elde etmek amacıyla iOS için MSAL kullanır.
applicationContext
doğrulandıktan sonra, belirteç alma süreci günlük kaydına işlenir.MSALSilentTokenParameters
kullanarak gerekli parametreleri tanımlar. Ardından belirteci sessizce almayı dener. Hatalar varsa kullanıcı etkileşimi gereksinimlerini denetler ve gerekirse etkileşimli bir işlem başlatır. Başarılı olduğunda,accessToken
özelliğini günceller ve yenilenen belirteci günlüğe kaydeder. Oturumu kapatma düğmesini etkinleştirerek işlemi tamamlar.
Oturumu kapatan kullanıcı
iOS için MSAL kullanarak iOS (Swift) uygulamanızdaki bir kullanıcının oturumunu kapatmak için aşağıdaki kodu kullanın:
@IBAction func signOut(_ sender: UIButton) {
guard let applicationContext = self.applicationContext else { return }
guard let account = self.currentAccount else { return }
guard let webViewParameters = self.webViewParameters else { return }
updateLogging(text: "Signing out...")
do {
/**
Removes all tokens from the cache for this application for the provided account
- account: The account to remove from the cache
*/
let signoutParameters = MSALSignoutParameters(webviewParameters: webViewParameters)
// If testing with Microsoft's shared device mode, trigger signout from browser. More details here:
// https://docs.microsoft.com/azure/active-directory/develop/msal-ios-shared-devices
if (self.currentDeviceMode == .shared) {
signoutParameters.signoutFromBrowser = true
} else {
signoutParameters.signoutFromBrowser = false
}
applicationContext.signout(with: account, signoutParameters: signoutParameters, completionBlock: {(success, error) in
if let error = error {
self.updateLogging(text: "Couldn't sign out account with error: \(error)")
return
}
self.updateLogging(text: "Sign out completed successfully")
self.accessToken = ""
self.updateCurrentAccount(account: nil)
})
}
}
Kod, applicationContext
, currentAccount
ve webViewParameters
varlığını doğrular. Daha sonra, çıkış yapma sürecini günlüğe kaydeder. Kod, sağlanan hesabın önbellekteki tüm belirteçlerini kaldırır. Geçerli cihaz moduna bağlı olarak, tarayıcıdan oturumun kapatılıp kapatılmayacağını belirler. Tamamlandıktan sonra log metnini uygun şekilde güncelleştirir. Oturumu kapatma işlemi sırasında bir hata oluşursa, hata iletisini günlüğe kaydeder. Oturumu başarıyla kapattıktan sonra erişim belirtecini boş bir değere günceller ve mevcut hesabı temizler.