Vi har åstadkommit mycket! I den föregående delen av serien fick vi igång mockservern så att vi kunde skicka en förfrågan från vår app och få ett JSON-svar.
För närvarande händer dock ingenting när vi loggar in. Vi skriver bara ut åtkomsttoken till konsolen och vi navigerar inte till appens startskärm som vi borde. I den här artikeln kommer vi att hantera auktorisering genom att implementera flera funktioner. Vår app måste kunna spara åtkomst- och uppdateringstoken på ett säkert sätt. Den måste också navigera till startskärmen efter inloggning och den måste komma ihåg vår session när vi loggar in, så att vi inte behöver ange ett användarnamn och lösenord varje gång vi startar appen.
Låt oss fundera på vad vi behöver för att få det här att fungera.
Först behöver vi en säker plats att förvara våra tokens. Det bästa stället att förvara dessa är Apple Keychain. Men istället för att arbeta direkt med nyckelringen kan vi förenkla processen genom att använda det här praktiska SwiftKeychainWrapper -biblioteket som tar hand om allt det tunga arbetet åt oss.
Så, låt oss installera det här biblioteket genom att lägga till pod 'SwiftKeychainWrapper' i vår Podfile och körs pod install, precis som vi gjorde tidigare med vårt SwiftLint-bibliotek.
På tal om SwiftLint vill vi inte få några linter-fel från våra Pods, eftersom vi i princip behandlar dem som svarta lådor och inte bryr oss om deras interna kod. Så låt oss exkludera alla Pods från linting genom att modifiera vårt .swiftlint.yml -skript så att det ser ut så här:
disabled_rules:
- trailing_whitespace
excluded:
- ${PWD}/PodsOch innan du säger det, ja, jag inaktiverade uttryckligen efterföljande_mellanslag regel från skräpet. Det är en väldigt irriterande regel, döm mig inte. 😛
Nästa steg är att definiera en klass som ska hantera vår auktorisering. Den måste kunna:
Låt oss skapa en singleton-hjälparklass som heter Auktorisering i Verksamhetsnyttiga tjänster mapp:
import Foundation
import SwiftKeychainWrapper
class Auth: ObservableObject {
struct Credentials {
var accessToken: String?
var refreshToken: String?
}
enum KeychainKey: String {
case accessToken
case refreshToken
}
static let shared: Auth = Auth()
private let keychain: KeychainWrapper = KeychainWrapper.standard
@Published var loggedIn: Bool = false
private init() {
loggedIn = hasAccessToken()
}
func getCredentials() -> Credentials {
return Credentials(
accessToken: keychain.string(forKey: KeychainKey.accessToken.rawValue),
refreshToken: keychain.string(forKey: KeychainKey.refreshToken.rawValue)
)
}
func setCredentials(accessToken: String, refreshToken: String) {
keychain.set(accessToken, forKey: KeychainKey.accessToken.rawValue)
keychain.set(refreshToken, forKey: KeychainKey.refreshToken.rawValue)
loggedIn = true
}
func hasAccessToken() -> Bool {
return getCredentials().accessToken != nil
}
func getAccessToken() -> String? {
return getCredentials().accessToken
}
func getRefreshToken() -> String? {
return getCredentials().refreshToken
}
func logout() {
KeychainWrapper.standard.removeObject(forKey: KeychainKey.accessToken.rawValue)
KeychainWrapper.standard.removeObject(forKey: KeychainKey.refreshToken.rawValue)
loggedIn = false
}
}Denna verktygsklass använder sig av SwiftNyckelringOmslag biblioteket för att ge oss de grundläggande auktoriseringsfunktionerna. Efter en lyckad inloggning anropar vi setCredentials() metod och skicka tokens som mottagits från svaret, så att de sparas i nyckelringen. Vi kommer också att ställa in vår inloggad flaggvariabel till sann, eftersom vår rotvy kommer att observera denna variabel för förändringar och navigera därefter från Inloggning skärmen till Hem skärmen. Mer om det senare. Vid utloggning tas tokens bort från nyckelringen, och inloggad variabeln är satt till falsk, vilket kommer att orsaka att vår Inloggningsskärm att dyka upp igen.
Koden i init() är mycket viktigt för att säkerställa att användarna inte behöver go genom inloggningsprocessen varje gång de startar appen. Om åtkomsttoken finns i nyckelringen när appen startas, så kommer inloggad Variabeln kommer att initieras till true, vilket säkerställer att användaren hoppar över inloggningsskärmen och landar på startskärmen.
Låt oss nu modifiera vår LoginViewModel så att den använder Auth-klassen för att ange våra inloggningsuppgifter.
import Foundation
class LoginViewModel: ObservableObject {
@Published var username: String = ""
@Published var password: String = ""
func login() {
LoginAction(
parameters: LoginRequest(
username: username,
password: password
)
).call { response in
Auth.shared.setCredentials(
accessToken: response.data.accessToken,
refreshToken: response.data.refreshToken
)
}
}
}Ser bra ut! Nu lagrar vi våra tokens i nyckelringen varje gång en användare loggar in. Men vi sitter fortfarande fast på inloggningsskärmen . Vi vill istället navigera till startskärmen , så låt oss göra det nu.
I Funktioner/Hem/Skärmar mapp, skapa en fil som heter Hemskärm.swift med följande innehåll:
import SwiftUI
struct HomeScreen: View {
@ObservedObject var viewModel: HomeViewModel = HomeViewModel()
var body: some View {
VStack {
Spacer()
Text("Home.Title".localized)
.font(.system(size: 24, weight: .bold, design: .default))
Spacer()
Button(
action: viewModel.logout,
label: {
Text("Home.LogoutButton.Title".localized)
.font(.system(size: 24, weight: .bold, design: .default))
.frame(maxWidth: .infinity, maxHeight: 60)
.foregroundColor(Color.white)
.background(Color.red)
.cornerRadius(10)
}
)
}
.padding(30)
}
}
struct HomeScreen_Previews: PreviewProvider {
static var previews: some View {
HomeScreen()
}
}Det är bara en enkel skärm som visar ett välkomstmeddelande och en utloggningsknapp. Vår HomeViewModel kommer att vara extremt enkel.
import Foundation
class HomeViewModel: ObservableObject {
func logout() {
Auth.shared.logout()
}
}Och här är den uppdaterade lokaliserbara filen:
"Login.UsernameField.Title" = "Användarnamn"; "Login.PasswordField.Title" = "Lösenord"; "Login.LoginButton.Title" = "Logga in"; "Home.Title" = "Välkommen!"; "Home.LogoutButton.Title" = "Logga ut";Nu ska vi implementera navigeringen. Vad vill vi uppnå? Vår rotskärm behöver växla mellan Inloggning skärmen och Hem skärmen, beroende på om användaren är inloggad eller inte. Som du kanske har gissat kommer vi att kontrollera värdet på variabeln inloggad i vår Auth-klass.
Vad är egentligen vår rotskärm? Det är det. InnehållsvyMen jag gillar att hålla ContentView rent och fritt från all logik eftersom det är vår ingångspunkt till appen, så vi skapar en annan skärm som innehåller den här logiken istället. Låt oss skapa en Rot funktionsmapp och lägg till en RootScreen fil till den:

Vår skärm kommer att ha följande kod:
import SwiftUI
struct RootScreen: View {
@EnvironmentObject var auth: Auth
var body: some View {
if auth.loggedIn {
HomeScreen()
} else {
LoginScreen()
}
}
}
struct RootScreen_Previews: PreviewProvider {
static var previews: some View {
RootScreen()
}
}Som ni kan se deklarerade vi vår observerbara Auktorisering klassinstans som MiljöObjekt, vilket innebär att vi kan lyssna på ändringarna i alla Auth-klassfält som är markerade som PubliceradI vårt fall är vi bara intresserade av förändringarna i inloggad variabel. När denna variabel ändras, vår RootScreen kommer att ritas om för att visa den högra skärmen (Hemskärm eller Inloggningsskärm), beroende på vad det nya värdet är.
Nu återstår bara att koppla ihop vår RootScreen med vår ContentView. Observera att när du använder en klass med MiljöObjekt egenskapsomslag, måste du deklarera den klassen i förfadervyn med miljöObjekt() modifierare så att din app kraschar inte när du öppnar den. Så här kommer ContentView att se ut efter våra uppdateringar:
import SwiftUI
struct ContentView: View {
var body: some View {
RootScreen()
.environmentObject(Auth.shared)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}Och det var allt! Nu kör vi appen för att testa hur den fungerar.

Voilà! Vi fick vad vi förväntade oss. Vi navigeras till startskärmen efter inloggning, och även om vi stänger och startar om vår app kommer den ihåg att vi var inloggade och omdirigerar oss tillbaka till startskärmen. Endast om vi klickar på Logga ut-knappen återgår vi till inloggningsskärmen.
Vi har avslutat det vi ville göra, så låt oss rensa upp lite nu. Först ska vi titta på Auth-klassen. Vi håller vår Referenser struktur och vår NyckelringNyckel enum i vår Auth-klass, vilket gör den större än den behöver vara. Låt oss placera dem i sina egna separata filer i vår Vanliga/Modeller mapp.

import Foundation
struct Credentials {
var accessToken: String?
var refreshToken: String?
}import Foundation
enum KeychainKey: String {
case accessToken
case refreshToken
}Nu ska vi ta en titt på våra inloggnings- och utloggningsknappar i våra inloggnings- och hemskärmsvyer.
Bortsett från bakgrundsfärgen har de i princip samma UI-kod! De har samma teckenstorlek, teckenbredd, knapphöjd, textfärg och hörnradie. Så, låt oss flytta den här gemensamma koden till en vymodifierare, så att vi kan återanvända detta gränssnitt och även få våra skärmar att se renare ut. Skapa en ViewModifiers mappen i din Gemensam mapp och lägg till en fil som heter Huvudknapp.swift:
import SwiftUI
struct MainButton: ViewModifier {
var color: Color = Color.blue
func body(content: Content) -> some View {
content
.font(.system(size: 24, weight: .bold, design: .default))
.frame(maxWidth: .infinity, maxHeight: 60)
.foregroundColor(Color.white)
.background(color)
.cornerRadius(10)
}
}Nu kan vi helt enkelt anropa denna vymodifierare på våra knappar.
...
Button(
action: viewModel.login,
label: {
Text("Login.LoginButton.Title".localized)
.modifier(MainButton())
}
)
......
Button(
action: viewModel.logout,
label: {
Text("Home.LogoutButton.Title".localized)
.modifier(MainButton(color: Color.red))
}
)
...Mycket snyggare! Du kan använda vymodifierare för att återanvända vanlig UI-kod på ett mycket elegant sätt.
Om du vill ladda ner ett projekt som innehåller allt vi har gjort hittills kan du göra det genom att klicka här .
” Bygg din första SwiftUI-app ” är en del av en artikelserie som är utformad för att hjälpa dig att komma igång med iOS-apputveckling.
Om du har några frågor kring någon av ovanstående tankar, dela dem gärna i kommentarsfältet.
Klicka här för att läsa del 1: Projektuppbyggnad
Klicka här för att läsa del 2: Projektarkitektur
Klicka här för att läsa del 3: Skapa inloggningsskärmen
Klicka här för att läsa del 4: Konfigurera en simulerad server med Postman
Vi har skapat ett sätt att hantera auktorisering, och i nästa artikel kommer vi att förbättra vår API-förfrågningskod genom att skapa en återanvändbar API-förfrågningsklass som kommer att användas i alla våra åtgärder! Så gör er redo för handling! 😎