使用 Swift decodable encodable 登录屏幕中的身份验证错误
Authentication Error in the login screen using Swift decodable encodable
使用 swiftui 和 rest api 构建新应用程序 iOS 应用程序构建的新手。在经历了许多 artilces 等之后为登录屏幕写了这篇文章
登录class
import Foundation
enum AuthenticationError: Error{
case invalidCredentials
case custom(errorMessage : String)
}
class SignIn {
struct LoginRequest : Codable
{
let UserName : String
let Password : String
}
struct LoginResponse : Codable
{
let AuthToken : String?
let Message : String?
let IsSuccess : Bool?
}
func SignInUser(UserName : String, Password : String, completion : @escaping (Result<String,
AuthenticationError>)->Void)
{
guard let url = URL(string: "http://xx.xxx.xxx.x:port/api/home/login")
else
{
completion(.failure(.custom(errorMessage: "Invalid URL")))
return
}
let body = LoginRequest (UserName: UserName, Password: Password)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let encodeData = try? JSONEncoder().encode(body)
print(String(data: encodeData!, encoding: .utf8)!)
request.httpBody = encodeData
URLSession.shared.dataTask(with: request) {(data, response, error) in
guard let data = data , error == nil else
{
completion(.failure(.custom(errorMessage: "No Data")))
return
}
guard let loginResponse = try? JSONDecoder().decode(LoginResponse.self, from: data)
else
{
completion(.failure(.invalidCredentials))
return
}
guard let token = loginResponse.AuthToken else
{
completion(.failure(.invalidCredentials))
return
}
completion(.success(token))
}.resume()
}
}
SignInViewModel
import Foundation
class SignInViewModel : ObservableObject {
@Published var username : String = ""
@Published var password : String = ""
func LogIn()
{
SignIn().SignInUser(UserName: username, Password: password)
{ **Line:#17**
result in
switch result{
case .success(let token):
print(token)
case .failure(let error):
print(error.localizedDescription)
}
}
}
}
SignInActivity
import SwiftUI
struct SignInActivity: View {
@StateObject private var loginVM = SignInViewModel()
@State private var Username:String = ""
@State private var Password:String = ""
var body: some View {
VStack(){
Image("logo").resizable().aspectRatio(contentMode:.fit)
Spacer()
Text("Welcome! Sign In to Continue ")
.font(.system(size: 20)).fontWeight(.semibold)
.foregroundColor(Color.blue)
Spacer()
VStack(){
HStack(alignment: .center){
Image(systemName: "person.circle.fill")
.foregroundColor(Color.blue)
.padding(.leading,8)
TextField(
"username", text:$loginVM.username)
.font(.system(size: 14))
.padding(.top,10)
.padding(.bottom,10)
// .overlay(VStack{
// Divider().offset(x:0,y:15)
// })
}.background(Color("text_bg"))
.cornerRadius(10)
.padding(.trailing,25)
.padding(.leading,25)
.padding(.bottom,15)
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
HStack(alignment: .center)
{
Image(systemName: "lock.circle.fill")
.foregroundColor(Color.green)
.padding(.leading,8)
TextField(
"password", text:$loginVM.password
).font(.system(size: 14))
.padding(.top,10)
.padding(.bottom,10)
// .overlay(VStack{
// Divider().offset(x:0,y:15)
// })
}.background(Color("text_bg"))
.cornerRadius(10)
.padding(.trailing,25)
.padding(.leading,25)
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
}
HStack()
{
Button(action: {
loginVM.LogIn()
})
{
Text("Sign In")
.padding(7)
.font(Font.system(size: 15))
.foregroundColor(.white).background(Color.green).cornerRadius(6).shadow(radius: 5)
}
}.padding(.top)
Spacer()
Spacer()
}.ignoresSafeArea(.keyboard)
}
API 工作正常,因为我已经在 android(已发布)中制作了完整的应用程序并且工作正常。现在尝试为 iOS.
制作应用程序
调试错误是
completion () 0x0000000106b27820 ScreenLearning`closure #1 (Swift.Result<Swift.String,
ScreenLearning.AuthenticationError>) -> () in ScreenLearning.SignInViewModel.LogIn() -> () at
SignInViewModel.swift:17
在 运行 上,错误是 AutheticationError 1。
无法弄清楚发生了什么。
要进行基本身份验证,请尝试使用以下方法,而不是将用户和密码作为 json 不安全地发送
在请求正文中。 (注意:用户名和密码小写)
func SignInUser(userName : String, password : String, completion : @escaping (Result<String, AuthenticationError>)->Void) {
// -- here
guard !userName.isEmpty && !password.isEmpty else {
completion(.failure(.custom(errorMessage: "Invalid userName or password")))
return
}
// -- here should use https
guard let url = URL(string: "http://xx.xxx.xxx.x:port/api/home/login")
else {
completion(.failure(.custom(errorMessage: "Invalid URL")))
return
}
// -- here
let hash = "\(userName):\(password)".data(using: .utf8)!.base64EncodedString()
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
// -- here
request.addValue("Basic \(hash)", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: request) {(data, response, error) in
guard let data = data , error == nil else{
completion(.failure(.custom(errorMessage: "No Data")))
return
}
guard let loginResponse = try? JSONDecoder().decode(LoginResponse.self, from: data)
else {
completion(.failure(.invalidCredentials))
return
}
// -- here
guard let token = loginResponse.ResponseData?.AuthToken else {
completion(.failure(.invalidCredentials))
return
}
completion(.success(token))
}.resume()
}
注意:您使用的是 http
而不是所需的 https
。
更改为 https
或在 Info.plist
中添加适当的 NSAppTransportSecurity
。
编辑:
注意,根据响应数据,你应该有这个型号:
struct ResponseData: Codable {
let AuthToken: String?
// ....
}
struct LoginResponse: Codable {
let Message: String?
let IsSuccess: Bool?
let ResponseData: ResponseData?
}
使用 swiftui 和 rest api 构建新应用程序 iOS 应用程序构建的新手。在经历了许多 artilces 等之后为登录屏幕写了这篇文章
登录class
import Foundation
enum AuthenticationError: Error{
case invalidCredentials
case custom(errorMessage : String)
}
class SignIn {
struct LoginRequest : Codable
{
let UserName : String
let Password : String
}
struct LoginResponse : Codable
{
let AuthToken : String?
let Message : String?
let IsSuccess : Bool?
}
func SignInUser(UserName : String, Password : String, completion : @escaping (Result<String,
AuthenticationError>)->Void)
{
guard let url = URL(string: "http://xx.xxx.xxx.x:port/api/home/login")
else
{
completion(.failure(.custom(errorMessage: "Invalid URL")))
return
}
let body = LoginRequest (UserName: UserName, Password: Password)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let encodeData = try? JSONEncoder().encode(body)
print(String(data: encodeData!, encoding: .utf8)!)
request.httpBody = encodeData
URLSession.shared.dataTask(with: request) {(data, response, error) in
guard let data = data , error == nil else
{
completion(.failure(.custom(errorMessage: "No Data")))
return
}
guard let loginResponse = try? JSONDecoder().decode(LoginResponse.self, from: data)
else
{
completion(.failure(.invalidCredentials))
return
}
guard let token = loginResponse.AuthToken else
{
completion(.failure(.invalidCredentials))
return
}
completion(.success(token))
}.resume()
}
}
SignInViewModel
import Foundation
class SignInViewModel : ObservableObject {
@Published var username : String = ""
@Published var password : String = ""
func LogIn()
{
SignIn().SignInUser(UserName: username, Password: password)
{ **Line:#17**
result in
switch result{
case .success(let token):
print(token)
case .failure(let error):
print(error.localizedDescription)
}
}
}
}
SignInActivity
import SwiftUI
struct SignInActivity: View {
@StateObject private var loginVM = SignInViewModel()
@State private var Username:String = ""
@State private var Password:String = ""
var body: some View {
VStack(){
Image("logo").resizable().aspectRatio(contentMode:.fit)
Spacer()
Text("Welcome! Sign In to Continue ")
.font(.system(size: 20)).fontWeight(.semibold)
.foregroundColor(Color.blue)
Spacer()
VStack(){
HStack(alignment: .center){
Image(systemName: "person.circle.fill")
.foregroundColor(Color.blue)
.padding(.leading,8)
TextField(
"username", text:$loginVM.username)
.font(.system(size: 14))
.padding(.top,10)
.padding(.bottom,10)
// .overlay(VStack{
// Divider().offset(x:0,y:15)
// })
}.background(Color("text_bg"))
.cornerRadius(10)
.padding(.trailing,25)
.padding(.leading,25)
.padding(.bottom,15)
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
HStack(alignment: .center)
{
Image(systemName: "lock.circle.fill")
.foregroundColor(Color.green)
.padding(.leading,8)
TextField(
"password", text:$loginVM.password
).font(.system(size: 14))
.padding(.top,10)
.padding(.bottom,10)
// .overlay(VStack{
// Divider().offset(x:0,y:15)
// })
}.background(Color("text_bg"))
.cornerRadius(10)
.padding(.trailing,25)
.padding(.leading,25)
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
}
HStack()
{
Button(action: {
loginVM.LogIn()
})
{
Text("Sign In")
.padding(7)
.font(Font.system(size: 15))
.foregroundColor(.white).background(Color.green).cornerRadius(6).shadow(radius: 5)
}
}.padding(.top)
Spacer()
Spacer()
}.ignoresSafeArea(.keyboard)
}
API 工作正常,因为我已经在 android(已发布)中制作了完整的应用程序并且工作正常。现在尝试为 iOS.
制作应用程序调试错误是
completion () 0x0000000106b27820 ScreenLearning`closure #1 (Swift.Result<Swift.String,
ScreenLearning.AuthenticationError>) -> () in ScreenLearning.SignInViewModel.LogIn() -> () at
SignInViewModel.swift:17
在 运行 上,错误是 AutheticationError 1。
无法弄清楚发生了什么。
要进行基本身份验证,请尝试使用以下方法,而不是将用户和密码作为 json 不安全地发送 在请求正文中。 (注意:用户名和密码小写)
func SignInUser(userName : String, password : String, completion : @escaping (Result<String, AuthenticationError>)->Void) {
// -- here
guard !userName.isEmpty && !password.isEmpty else {
completion(.failure(.custom(errorMessage: "Invalid userName or password")))
return
}
// -- here should use https
guard let url = URL(string: "http://xx.xxx.xxx.x:port/api/home/login")
else {
completion(.failure(.custom(errorMessage: "Invalid URL")))
return
}
// -- here
let hash = "\(userName):\(password)".data(using: .utf8)!.base64EncodedString()
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
// -- here
request.addValue("Basic \(hash)", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: request) {(data, response, error) in
guard let data = data , error == nil else{
completion(.failure(.custom(errorMessage: "No Data")))
return
}
guard let loginResponse = try? JSONDecoder().decode(LoginResponse.self, from: data)
else {
completion(.failure(.invalidCredentials))
return
}
// -- here
guard let token = loginResponse.ResponseData?.AuthToken else {
completion(.failure(.invalidCredentials))
return
}
completion(.success(token))
}.resume()
}
注意:您使用的是 http
而不是所需的 https
。
更改为 https
或在 Info.plist
中添加适当的 NSAppTransportSecurity
。
编辑:
注意,根据响应数据,你应该有这个型号:
struct ResponseData: Codable {
let AuthToken: String?
// ....
}
struct LoginResponse: Codable {
let Message: String?
let IsSuccess: Bool?
let ResponseData: ResponseData?
}