No se llama al método de proxy de inicio de sesión de Apple didCompleteWithAuthorization, didCompleteWithError no funciona



这两个方法都没有调用。
///回调成功
-(void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)){
}



///回调失败

-(void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0)){}

En resumen, tengo un problema al hacer esto.

Pregunta 1: ¿No se llama al método de proxy de inicio de sesión didCompleteWithAuthorization de Apple y no se llama a didCompleteWithError?

Solución: después de la prueba, descubrí que mi código para manejar el inicio de sesión de Apple no se llama cuando está escrito en una clase que hereda NSObject. Se puede llamar con éxito cuando se reemplaza heredando UIViewController. O continúe usando la herencia NSObject, pero esta clase se puede llamar con éxito si está escrita con interés simple. Ejemplo de código de interés simple


//  GSSignWithApple.h 文件

@interface GSSignWithApple : NSObject


+ (GSSignWithApple *)SharedManager;

@end





//  GSSignWithApple.m 文件

+ (GSSignWithApple *)SharedManager{
    static GSSignWithApple *manager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        //不能再使用alloc方法
        //因为已经重写了allocWithZone方法,所以这里要调用父类的分配空间的方法
    manager = [[super allocWithZone:NULL] init];
    });
    return manager;
}



// 防止外部调用alloc 或者 new
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    return [GSSignWithApple SharedManager];
}

//下面是初始化和 几个代理方法 和 点击事件的处理 

Pregunta 2: ¿Se puede escribir sin ASAuthorizationAppleIDButton? ¿Es posible escribir con UIUButtom? ¿Cómo se llama a la interfaz de usuario con el botón escrito en h5?

Respuesta: Ambos están bien.

Lo he probado todo aquí. Puede ser llamado. Mi página aquí está escrita por H5, no hay ningún botón para inicializar, directamente desde el botón habitual, haga clic en el código de evento para escribir de la siguiente manera



//这块代码一般是初始化苹果登陆按钮后,苹果按钮的点击事件。后面的步骤跟正常的苹果登陆代码一样。
-(void)click API_AVAILABLE(ios(13.0)){

    ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc]init];

    ASAuthorizationAppleIDRequest *request = [appleIDProvider createRequest];

    request.requestedScopes = @[ASAuthorizationScopeFullName,ASAuthorizationScopeEmail];

    ASAuthorizationController *auth = [[ASAuthorizationController alloc]initWithAuthorizationRequests:@[request]];

    auth.delegate = self;

    auth.presentationContextProvider = self;

    [auth performRequests];

}

 

Pregunta 3: ¿De qué es responsable iOS y cuál es la complejidad del fondo? Mirando específicamente el siguiente artículo, iOS es el principal responsable de obtener la información del usuario y el token y el código, que deben pasarse a un segundo plano, que debe estar conectado a la interfaz del sitio web oficial de Apple. De hecho, es similar a los pasos para acoplar el inicio de sesión de WeChat. Es solo que la verificación de cifrado de Apple es más engorrosa.

 

 

Los siguientes son los pasos de implementación específicos. Copio el de otra persona.

Autor yuyangkk      https://www.jianshu.com/p/12aade4d053b

Autor 72 líneas de código     https://www.jianshu.com/p/e1284bd8c72a

 

1. Antecedentes

De acuerdo con los requisitos de las pautas de auditoría de Apple, cualquier persona que acceda al inicio de sesión de tres partes debe acceder al inicio de sesión autorizado de Apple. Como nuestra aplicación está conectada al inicio de sesión de WeChat, agregamos el inicio de sesión de Apple según sea necesario.

Apple Review Guide-4.8 Inicio de sesión a través de Apple
Si la aplicación utiliza un servicio de inicio de sesión social o de terceros (por ejemplo, inicio de sesión de Facebook, inicio de sesión de Google, inicio de sesión a través de Twitter, inicio de sesión a través de LinkedIn, inicio de sesión a través de Amazon o WeChat) para configurar o verificar esto La cuenta de usuario principal de la aplicación, la aplicación también debe proporcionar "Iniciar sesión con Apple" como una opción equivalente. La cuenta principal del usuario se refiere a la cuenta establecida en la aplicación para identificación, inicio de sesión y acceso a funciones y servicios relacionados.
En los siguientes casos, la opción de "Iniciar sesión con Apple" no es necesaria:
su aplicación solo utiliza la configuración de la cuenta de la empresa y el sistema de inicio de sesión.
Su aplicación es una aplicación educativa, empresarial o comercial, y requiere que los usuarios inicien sesión con una cuenta educativa o empresarial existente.
Su aplicación utiliza un sistema de ciudadanía o una tarjeta de identificación electrónica respaldados por el gobierno o la industria para autenticar a los usuarios.
Su aplicación es un cliente de un servicio de terceros específico y los usuarios deben iniciar sesión directamente con su correo electrónico, redes sociales u otras cuentas de terceros para acceder al contenido.

2. Preparación para el acceso

2.1 Sitio web para desarrolladores, abra el correspondiente Iniciar sesión con Apple

Marque Iniciar sesión con Apple, haga clic en Editar

2.1.1 Aplicación existente.png

Marque Habilitar como ID de aplicación principal

2.1.2 habilitar como id.png de Apple principal

2.2 Crea una clave privada para generar client_secret en segundo plano

2.2.1key.png

Complete el Nombre de la clave, marque Iniciar sesión con Apple, haga clic en Configurar

2.2.2 Complete la información clave.png

Seleccione la ID de la aplicación correspondiente, haga clic en Guardar

2.2.3 Configurar clave privada.png

Elija continuar

2.2.4 elegir continuar

registrado

 

2.2.5 Registro

Haga clic en Descargar para descargar la clave privada, que solo se puede descargar una vez

2.2.6 Descargar

2.2.7. Mantener keyid

También puede volver a la lista de claves, hacer clic en la clave que acabamos de crear, ver la identificación de la clave, copiarla y guardarla para una copia de seguridad

2.2.8. Ver keyid.png

2.3. Xcode 开启 Iniciar sesión con Apple

2.3.Xcode 添加 Iniciar sesión con Apple.png

3. Diagrama de secuencia de acceso

Un diagrama de secuencia de inicio de sesión irregular de Apple.png

De hecho, podemos verificar de dos maneras:
Solución 1: Nuestra aplicación verifica por sí misma, analiza el ID de usuario y el IdentityToken devueltos por el SDK y luego envía el ID de usuario al backend, y el backend realiza una consulta a la base de datos y devuelve la información de enlace. Esto es relativamente sencillo.
Solución 2: La aplicación obtiene el código de autorización devuelto por el SDK y lo entrega al backend. El backend verifica la interfaz https://appleid.apple.com/auth/token , devuelve id_token, analiza el token y devuelve la información de enlace. Este relativamente complejo

4. Trabaja en iOS

La autorización generalmente requiere los siguientes pasos:

  1. Importar biblioteca de autorización # import <AuthenticationServices / AuthenticationServices.h>
  2. Agregue un evento de respuesta para evocar la interfaz de autorización de Apple
  3. Verificar contraseña o identificación de biografía
  4. Pase la verificación y pase el resultado de la devolución de llamada al fondo

Primero, agregue un botón de evento:

 

- (void)createAppleIDLoginButton{
    if (@available(iOS 13.0, *)) {
        self.appleLoginButton = [[ASAuthorizationAppleIDButton alloc] initWithAuthorizationButtonType:ASAuthorizationAppleIDButtonTypeSignIn authorizationButtonStyle:ASAuthorizationAppleIDButtonStyleWhiteOutline];
        [self.appleLoginButton addTarget:self action:@selector(signinWithApple) forControlEvents:UIControlEventTouchUpInside];
        [loginButtonView addSubview:self.appleLoginButton];
    }
}

// 唤起苹果登录
- (void)signinWithApple API_AVAILABLE(ios(13.0)){
    // 创建登录请求
    ASAuthorizationAppleIDRequest *idRequest = [[[ASAuthorizationAppleIDProvider alloc] init] createRequest];
    // 创建iCloud 密码填充登录,可不创建
    ASAuthorizationPasswordRequest *passwordRequest = [[[ASAuthorizationPasswordProvider alloc] init] createRequest];
    // 请求的用户数据
    idRequest.requestedScopes = @[ASAuthorizationScopeFullName,ASAuthorizationScopeEmail];
    // 如果不需要iCloud密码登录,不添加passwordRequest
    ASAuthorizationController *controller = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[idRequest,passwordRequest]];
    controller.delegate = self;
    controller.presentationContextProvider = self;
    [controller performRequests];
}

- (void)handleAppleResponse:(ASAuthorizationAppleIDCredential *)credential API_AVAILABLE(ios(13.0)){
    // 将返回的数据,提交给后台
}

En segundo lugar, siguiendo el agente ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProvidingy el agente para lograr la devolución de llamada:

 

#pragma mark - ASAuthorizationControllerDelegate
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)){
    if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]])       {
        ASAuthorizationAppleIDCredential *credential = authorization.credential;
        
        NSString *state = credential.state;
        NSString *user = credential.user;
        NSPersonNameComponents *fullName = credential.fullName;
        NSString *email = credential.email;
        NSString *authorizationCode = [[NSString alloc] initWithData:credential.authorizationCode encoding:NSUTF8StringEncoding]; // refresh token
        NSString *identityToken = [[NSString alloc] initWithData:credential.identityToken encoding:NSUTF8StringEncoding]; // access token
        ASUserDetectionStatus realUserStatus = credential.realUserStatus;
        
        Log(@"state: %@", state);
        Log(@"user: %@", user);
        Log(@"fullName: %@", fullName);
        Log(@"email: %@", email);
        Log(@"authorizationCode: %@", authorizationCode);
        Log(@"identityToken: %@", identityToken);
        Log(@"realUserStatus: %@", @(realUserStatus));

        // 数据处理
        [self handleAppleResponse:credential];
    }
  //else if([authorization.credential isKindOfClass:ASPasswordCredential.class]) {
        //ASPasswordCredential *credential = authorization.credential;
        //Log(@"user:%@", credential.user);
        //Log(@"password:%@", credential.password);
    //}
}

- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0)){
    NSString *errorMsg = nil;
    switch (error.code) {
        case ASAuthorizationErrorCanceled:
            errorMsg = @"用户取消了授权请求";
            break;
        case ASAuthorizationErrorFailed:
            errorMsg = @"授权请求失败";
            break;
        case ASAuthorizationErrorInvalidResponse:
            errorMsg = @"授权请求响应无效";
            break;
        case ASAuthorizationErrorNotHandled:
            errorMsg = @"未能处理授权请求";
            break;
        case ASAuthorizationErrorUnknown:
            errorMsg = @"授权请求失败未知原因";
            break;
    }
    Log(@"%@", errorMsg);
}

#pragma mark - ASAuthorizationControllerPresentationContextProviding
- (ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller API_AVAILABLE(ios(13.0)){
    return self.window;
}

Primero evoca la interfaz.PNG

Después de la autorización, se volverá a abrir la interfaz. PNG

5. Labor de antecedentes

Reciba y verifique el resultado de la autorización de iOS, solicite id_token del servicio de Apple, el proceso general es:

5.1 Proporcionar una interfaz para recibir usuario (identificador único), identityToken, AuthorizationCode y realizar la verificación de la firma;

Utilice la clave web Json proporcionada por Apple para generar la clave pública y verificar el identityToken pasado por el cliente.

Dirección de clave pública: https://appleid.apple.com/auth/keys , necesitamos convertir a clave pública, dirección de referencia de conversión de clave pública: https://8gwifi.org/jwkconvertfunctions.jsp

 

{
  "keys": [
    {
      "kty": "RSA",
      "kid": "AIDOPK1",
      "use": "sig",
      "alg": "RS256",
      "n": "lxrwmuYSAsTfn-lUu4goZSXBD9ackM9OJuwUVQHmbZo6GW4Fu_auUdN5zI7Y1dEDfgt7m7QXWbHuMD01HLnD4eRtY-RNwCWdjNfEaY_esUPY3OVMrNDI15Ns13xspWS3q-13kdGv9jHI28P87RvMpjz_JCpQ5IM44oSyRnYtVJO-320SB8E2Bw92pmrenbp67KRUzTEVfGU4-obP5RZ09OxvCr1io4KJvEOjDJuuoClF66AT72WymtoMdwzUmhINjR0XSqK6H0MdWsjw7ysyd_JhmqX5CAaT9Pgi0J8lU_pcl215oANqjy7Ob-VMhug9eGyxAWVfu_1u6QJKePlE-w",
      "e": "AQAB"
    }
  ]
}

Para verificar el token de identidad, el servidor debe:
usar la clave pública del servidor para verificar la firma JWS E256,
verificar el número aleatorio para la autenticación ( código de autorización)
verificar que el campo iss contiene https://appleid.apple.com
confirmar que el campo aud es el client_id del desarrollador (ID del paquete) El
tiempo de verificación es anterior al valor exp del token

5.2. Generar client_secret en formato JWT requerido por el servidor de Apple para verificar la legitimidad;
parámetros requeridos para la generación de client_secret:
clave privada: creada en la cuenta de desarrollador de Apple, solo se puede descargar una vez (formato .P8), es necesario mantener
alg: algoritmo "ES256"
niño: ID de clave privada, el key_id correspondiente a la clave privada creada en la cuenta de desarrollador de Apple
iss: team_id, el ID de equipo obtenido de la cuenta de desarrollador de Apple
iat: key start time, UTC seconds
exp: key expiration time, su valor no debe ser mayor que el servidor 15777000 (6 meses, en segundos) del tiempo actual de Unix en el
aud: valor fijo " https://appleid.apple.com "
sub: id del paquete

Una vez creado el token, se firma utilizando el algoritmo de firma digital de curva elíptica con curva P-256 (ECDSA) y el algoritmo hash SHA-256. Especifique el valor ES256 en la clave del título del algoritmo. Especifique el identificador de clave en el atributo de niño.

5.3. Verificar los datos devueltos por el backend de Apple a través de la interfaz https://appleid.apple.com/auth/token y los datos transmitidos por el cliente a través de la interfaz.

Puede verificar el token de actualización como máximo una vez al día para confirmar que la ID de Apple del usuario en el dispositivo aún mantiene una buena reputación en los servidores de Apple. Si intenta verificar el ID de Apple del usuario varias veces al día, los servidores de Apple pueden restringir sus llamadas.

Puede verificar el token de actualización hasta una vez al día para confirmar que la ID de Apple del usuario en ese dispositivo todavía está en regla con los servidores de Apple. Los servidores de Apple pueden acelerar su llamada si intenta verificar la ID de Apple de un usuario más de una vez al día.

Parámetros:
client_id: cadena de identificación del paquete del cliente, que es pública para los tokens de autorización y actualización, y debe pasarse.
client_secret: la cadena de firma JWT generada en el paso anterior, que es pública para los tokens de autorización y actualización y debe pasarse.
código: El código de autorización pasado por el cliente, dedicado para autorización, uso único y válido por 5 minutos.
grant_type: se debe pasar el tipo de interacción cliente-servidor, cadena fija, común para los tokens de autorización y actualización. Autorizar para pasar "código_autorización", actualizar el Token con "actualizar_token".
refresh_token: el token que se usa para actualizar el token, que se usa al actualizar el token.
redirect_uri: la URL de redireccionamiento utilizada para la autorización, que se utiliza cuando la web inicia sesión con AppleID. Si está utilizando la web, complete la Configuración de autenticación web cuando configure el inicio de sesión con appleid en el sitio web del desarrollador, y no es necesario pasarlo de forma nativa.

Datos devueltos por los antecedentes de Apple:

 

{
  "access_token": "一个token,此处省略",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "一个token,此处省略",
  "id_token": "结果是JWT,字符串形式,此处省略"
}

//示例:
{

    "access_token": "ac6dd62539f5441cdacd7b548a9fe33a9.0.nrszq.gCD9GEmcznYjt5m3h4UkEg",
    "token_type": "Bearer",
    "expires_in": 3600,
    "refresh_token": "r9f10xxxxxxxxxxxe80e.0.nxxxxq.fk7Q1ZxxxxxxxxxM0w",
    "id_token": "eyJraWQiOiJlWGF1bm1MIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiY29tLnpvZnVuZC5xaWFuZ3VuZ3VuIiwiZXhwIjoxNTgzMTMxNzI1LCJpYXQiOjE1ODMxMzExMjUsInN1YiI6IjAwMTI5MC44MDYzZGRmODMwYjI0YTQ5OTc4OTZhNmUxOGNmMjE5Yi4xMDEzIiwiYXRfaGFzaCI6IjBrU05fMzlkcGxhUEdnMUd0YV9Ka1EiLCJlbWFpbCI6InJlZXM5cGd3NWJAcHJpdmF0ZXJlbGF5LmFwcGxlaWQuY29tIiwiZW1haWxfdmVyaWZpZWQiOiJ0cnVlIiwiaXNfcHJpdmF0ZV9lbWFpbCI6InRydWUiLCJhdXRoX3RpbWUiOjE1ODMxMzEwOTV9.p19sc-tjsNQNCXyb33AX9r4oXj1xA4EmKh9Yp5E5ImxnOe6n_ISqvgMyDGqOuZwLAP9iMfB4-S_--1dpuzPx4HtwOyygpHhZSEZ4GcynCpHg6MFC7Mlkcn34J_awEXPeox_nJMRPRMN-ydQ7GxLvSrEJPJ-1rL473pIBc-DyNdYjkXcuyVU4FN6nEuh2NrOKCzMjkeEDqSmL2nG_TM7qE7JscAOcI6Nv5oml2KkYMeQl24kopQa2rC3m8HSsYSdaPs04pdiFEF20Fl3RqR-cnE0UeTmlC4KaBRF4xGpPpNT-OKvW2P6yUrkHmS27Mt1vM1sJkCiKMUGO3_i0Ef7ghA"
}

Base64 decodifica el encabezado y la carga útil en id_token para obtener la información correspondiente:

 

header: 
{
"kid":"eXaunmL",
"alg":"RS256"
} 
payload:
{
"iss":"https://appleid.apple.com",
"aud":"com.qiangungun",
"exp":1582880575,
"iat":1582879975,
"sub":"这个字段和客户端拿到的user以及identityToken第二段base64解码出来的sub相同",
"at_hash":"8_moKGpSUFG-zueTcf5EjQ",
"email":"[email protected]",
"email_verified":"true",
"is_private_email":"true",
"auth_time":1582879944
}

Al comparar el usuario enviado desde el cliente con el sub en la carga útil, puede determinar si es un usuario unificado

5.4. Se pasa la verificación y se devuelve el estado vinculante o el estado de registro

Si se ha vinculado, devolverá sessionId y userId.
Si no se ha vinculado, devolverá información similar a la requerida para el inicio de sesión de WeChat, y el cliente realizará la operación de vinculación.



Autor: yuyangkk
enlace: https: //www.jianshu.com/p/12aade4d053b
Fuente: Los libros de Jane
tienen derechos de autor del autor. Para reimpresiones comerciales, comuníquese con el autor para obtener autorización. Para reimpresiones no comerciales, indique la fuente.

 

Supongo que te gusta

Origin blog.csdn.net/ximiaoweilai/article/details/108843522
Recomendado
Clasificación