Update auth documentation

This commit is contained in:
Daniel Saidi 2021-09-08 11:06:16 +02:00
parent 9df955bebc
commit 50e30153bc
6 changed files with 62 additions and 23 deletions

View File

@ -11,9 +11,9 @@ import Foundation
/**
This struct represents a unique authentication.
This struct currently only has an `id` but it is still used
to be able to extend the authentication information without
having to change any authentication protocols.
This struct currently only has an `id` but is still used to
be able to extend the authentication info without having to
change any authentication protocols.
*/
public struct Authentication {

View File

@ -20,7 +20,8 @@ public protocol AuthenticationService: AnyObject {
/**
Authenticate the user for a certain authentication type.
`reason` can be used as display information to the user.
`reason` can be used to display information to the user.
*/
func authenticateUser(for auth: Authentication, reason: String, completion: @escaping AuthCompletion)

View File

@ -29,6 +29,13 @@ public class BiometricAuthenticationService: AuthenticationService {
// MARK: - Public functions
/**
Authenticate the user for a certain authentication type,
provided that the service can authenticate the user for
the provided authentication type.
`reason` can be used to display information to the user.
*/
public func authenticateUser(for auth: Authentication, reason: String, completion: @escaping AuthCompletion) {
guard canAuthenticateUser(for: auth) else { return completion(.failure(AuthError.unsupportedAuthentication)) }
performAuthentication(for: auth, reason: reason) { result in
@ -36,11 +43,23 @@ public class BiometricAuthenticationService: AuthenticationService {
}
}
/**
Check if the service instance can authenticate the user
for a certain authentication type.
*/
public func canAuthenticateUser(for auth: Authentication) -> Bool {
var error: NSError?
return LAContext().canEvaluatePolicy(policy, error: &error)
}
/**
Authenticate the user for a certain authentication type,
regardless of if this service can authenticate the user
for the provided authentication type or not.
This is a way to bypass any particular rules and states
of the service and is not part of the service protocol.
*/
public func performAuthentication(for auth: Authentication, reason: String, completion: @escaping AuthCompletion) {
LAContext().evaluatePolicy(policy, localizedReason: reason) { result, error in
if let error = error { return completion(.failure(error)) }

View File

@ -18,7 +18,7 @@ import Foundation
to perform biometric authentication to access critical data.
Note that you can't rely on a cached authentication service
to clear its cached state. Call `resetUserAuthentication()`
to clear its cached state. Call `resetUserAuthentications()`
or `resetUserAuthentication(for:)` as soon as this state is
considered to be invalid, e.g. when your app is send to the
background and a new user can open the app at a later time.
@ -26,19 +26,20 @@ import Foundation
public protocol CachedAuthenticationService: AuthenticationService {
/**
Check if the user has already been authenticated for an
authentication type.
Check if the service has already authenticated the user
for a certain authentication type.
*/
func isUserAuthenticated(for auth: Authentication) -> Bool
/**
Reset the user's entire authentication state.
*/
func resetUserAuthentication()
/**
Reset the user's authentication state for a single type
of authentication.
Reset the service's cached authentication state for the
provided authentication type.
*/
func resetUserAuthentication(for auth: Authentication)
/**
Reset the service's cached authentication state for all
authentication types.
*/
func resetUserAuthentications()
}

View File

@ -10,10 +10,7 @@ import Foundation
/**
This service wraps another authentication service and keeps
authentication results in a cache. `resetUserAuthentication`
can be called to clear one or all caches and force users to
perform new authentications to , e.g. after sending the app
to the background.
authentication results in a cache.
*/
public class CachedAuthenticationServiceProxy: CachedAuthenticationService {
@ -34,6 +31,11 @@ public class CachedAuthenticationServiceProxy: CachedAuthenticationService {
// MARK: - Functions
/**
Authenticate the user for a certain authentication type.
`reason` can be used to display information to the user.
*/
public func authenticateUser(for auth: Authentication, reason: String, completion: @escaping AuthCompletion) {
if isUserAuthenticated(for: auth) { return completion(.success(())) }
baseService.authenticateUser(for: auth, reason: reason) { result in
@ -42,21 +44,37 @@ public class CachedAuthenticationServiceProxy: CachedAuthenticationService {
}
}
/**
Check if the service instance can authenticate the user
for a certain authentication type.
*/
public func canAuthenticateUser(for auth: Authentication) -> Bool {
baseService.canAuthenticateUser(for: auth)
}
/**
Check if the service has already authenticated the user
for a certain authentication type.
*/
public func isUserAuthenticated(for auth: Authentication) -> Bool {
cache[auth.id] ?? false
}
public func resetUserAuthentication() {
cache.removeAll()
}
/**
Reset the service's cached authentication state for the
provided authentication type.
*/
public func resetUserAuthentication(for auth: Authentication) {
setIsAuthenticated(false, for: auth)
}
/**
Reset the service's cached authentication state for all
authentication types.
*/
public func resetUserAuthentications() {
cache.removeAll()
}
}

View File

@ -115,7 +115,7 @@ class CachedAuthenticationServiceProxyTests: QuickSpec {
service.authenticateUser(for: auth, reason: "") { _ in
expect(service.isUserAuthenticated(for: .standard)).to(beTrue())
expect(service.isUserAuthenticated(for: auth)).to(beTrue())
service.resetUserAuthentication()
service.resetUserAuthentications()
expect(service.isUserAuthenticated(for: .standard)).to(beFalse())
expect(service.isUserAuthenticated(for: auth)).to(beFalse())
asyncTrigger.trigger()