O método de proxy de login da Apple didCompleteWithAuthorization não é chamado, didCompleteWithError não vai



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



///回调失败

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

Para resumir, tenho um problema ao fazer isso.

Pergunta 1: O método de proxy de login da Apple didCompleteWithAuthorization não é chamado e didCompleteWithError não é chamado?

Solução: após o teste, descobri que meu código para lidar com o login da Apple não é chamado quando é escrito em uma classe que herda NSObject. Ele pode ser chamado com êxito quando substituído pelo UIViewController herdado. Ou continue a usar o NSObject de herança, mas esta classe pode ser chamada com sucesso se for escrita com juros simples. Exemplo de código de interesse simples


//  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];
}

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

Pergunta 2: Pode ser escrito sem ASAuthorizationAppleIDButton? Posso escrever com UIUButtom? Como a IU é chamada com o botão escrito em h5?

Resposta: Ambos estão bem.

Eu tentei de tudo aqui. Pode ser chamado. Minha página aqui foi escrita por H5, não há botão para inicializar, diretamente do código de evento de clique de botão usual para escrever como segue



//这块代码一般是初始化苹果登陆按钮后,苹果按钮的点击事件。后面的步骤跟正常的苹果登陆代码一样。
-(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];

}

 

Pergunta 3: pelo que o iOS é responsável e qual é a complexidade do plano de fundo? Observando especificamente o artigo a seguir, o iOS é o principal responsável por obter informações do usuário, tokens e códigos, que devem ser passados ​​para segundo plano, que deve ser conectado à interface do site oficial da Apple. Na verdade, é semelhante às etapas de encaixe do login do WeChat. Acontece que a verificação de criptografia da Apple é mais complicada.

 

 

A seguir estão as etapas de implementação específicas. Eu copio o de outra pessoa.

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

Autor de 72 linhas de código     https://www.jianshu.com/p/e1284 Budapc72a

 

1. Fundo

De acordo com os requisitos das diretrizes de revisão da Apple, qualquer pessoa que acessar o login de três partes deve acessar o login autorizado da Apple. Como nosso aplicativo está conectado ao login do WeChat, adicionamos o login da Apple conforme necessário.

Apple Audit Guide-4.8 Login via Apple
Se o aplicativo usa um serviço de login social ou de terceiros (por exemplo, login do Facebook, login do Google, login via Twitter, login via LinkedIn, login via Amazon ou WeChat) para configurar ou verificar isso A conta de usuário principal do aplicativo, o aplicativo também deve fornecer "Login com a Apple" como uma opção equivalente. A conta principal do usuário se refere à conta estabelecida no aplicativo para identificação, login e acesso às funções e serviços relacionados.
Nos seguintes casos, a opção "Entrar com Apple" não é necessária:
seu aplicativo usa apenas as configurações de conta e sistema de login da própria empresa.
Seu aplicativo é educacional, empresarial ou empresarial e exige que os usuários façam login com uma conta existente de educação ou empresa.
Seu aplicativo usa um sistema de cidadania com suporte do governo ou da indústria ou carteira de identidade eletrônica para autenticar usuários.
Seu aplicativo é um cliente de um serviço de terceiros específico e os usuários precisam fazer login diretamente com seu e-mail, mídia social ou outras contas de terceiros para acessar o conteúdo.

2. Preparação para acesso

2.1 Site do desenvolvedor, abra o Sign in With Apple correspondente

Marque Sign In With Apple, clique em Edit

2.1.1 App.png Existente

Marque Habilitar como ID de aplicativo principal

2.1.2 habilitar como apple id.png primário

2.2 Crie uma chave privada para gerar client_secret em segundo plano

2.2.1key.png

Preencha KeyName, marque Sign In With Apple, clique em Configure

2.2.2 Preencha key information.png

Selecione o ID do aplicativo correspondente e clique em Salvar

2.2.3 Configurar chave privada.png

Escolha continuar

2.2.4 escolha continuar

registrado

 

2.2.5 Registro

Clique em Download para baixar a chave privada, que só pode ser baixada uma vez

2.2.6 Download

2.2.7. Manter keyid

Você também pode voltar para a lista de chaves, clicar na chave que acabamos de criar, visualizar a ID da chave, copiar e salvá-la para backup

2.2.8. Exibir keyid.png

2.3. Xcode 开启 Faça login com a Apple

2.3.Xcode 添加 Faça login com Apple.png

3. Diagrama de sequência de acesso

Um diagrama de sequência de login irregular da Apple.png

Na verdade, podemos verificar de duas maneiras:
Solução 1: Nosso aplicativo verifica por si mesmo, analisa o userid e o identityToken retornados pelo SDK e, em seguida, envia o userId para o segundo plano, que realiza uma consulta ao banco de dados e retorna as informações de ligação. Isso é relativamente simples.
Solução 2: o aplicativo obtém o código de autorização retornado pelo SDK e o entrega ao back-end. O back-end verifica por meio da interface https://appleid.apple.com/auth/token , retorna id_token, analisa o token e retorna as informações de ligação. Este relativamente complexo

4. Trabalho em iOS

A autorização geralmente requer as seguintes etapas:

  1. Biblioteca de autorização de importação # import <AuthenticationServices / AuthenticationServices.h>
  2. Adicionar evento de resposta para evocar interface de autorização Apple
  3. Verifique a senha ou ID de bio
  4. Passe a verificação e passe o resultado do retorno de chamada para segundo plano

Primeiro, adicione um botão 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)){
    // 将返回的数据,提交给后台
}

Em segundo lugar, seguindo o agente ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProvidingeo agente para alcançar o retorno de chamada:

 

#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;
}

Primeiro evoque a interface.PNG

Após a autorização, a interface será novamente chamada.

5. Trabalho de fundo

Receba e verifique o resultado da autorização do iOS, solicite id_token do serviço da Apple, o processo geral é:

5.1. Fornecer uma interface para receber o usuário (identificador único), identityToken, autorizaçãoCode e executar verificação de assinatura;

Use a Json Web Key fornecida pela Apple para gerar a chave pública e verificar o identityToken passado pelo cliente.

Endereço de chave pública: https://appleid.apple.com/auth/keys , precisamos converter em chave pública, endereço de referência de conversão de chave 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 o token de identidade, o servidor deve:
usar a chave pública do servidor para verificar a assinatura JWS E256,
verificar o número aleatório para autenticação ( código de autorização)
verificar se o campo iss contém https://appleid.apple.com
confirmar que o campo aud é o client_id do desenvolvedor (id do pacote) O
tempo de verificação é anterior ao valor exp do token

5.2. Gerar client_secret no formato JWT exigido pelo servidor Apple para verificar a legitimidade;
parâmetros necessários para geração
client_secret : privatekey: criado na conta de desenvolvedor da Apple, só pode ser baixado uma vez (formato .P8), é necessário manter
alg: algoritmo "ES256"
garoto: ID da chave privada, o key_id correspondente à chave privada criada na conta do desenvolvedor da Apple
iss: team_id, o ID da equipe obtido da conta do desenvolvedor da Apple
iat: hora de início da chave, segundos UTC
exp: tempo de expiração da chave, seu valor não deve ser maior que o servidor 15777000 (6 meses, em segundos) do tempo Unix atual no
aud: valor fixo " https://appleid.apple.com "
sub: id do pacote

Depois que o token é criado, ele é assinado usando o algoritmo de assinatura digital de curva elíptica com curva P-256 (ECDSA) e o algoritmo de hash SHA-256. Especifique o valor ES256 na chave do título do algoritmo. Especifique o identificador de chave no atributo kid.

5.3. Verifique os dados retornados pelo back-end da Apple por meio da interface https://appleid.apple.com/auth/token e os dados transmitidos pelo cliente por meio da interface

Você pode verificar o token de atualização no máximo uma vez por dia para confirmar se o ID Apple do usuário no dispositivo ainda mantém uma boa reputação nos servidores da Apple. Se você tentar verificar o ID Apple do usuário várias vezes ao dia, os servidores da Apple podem restringir suas chamadas.

Você pode verificar o token de atualização até uma vez por dia para confirmar se o ID Apple do usuário naquele dispositivo ainda está em dia com os servidores da Apple. Os servidores da Apple podem limitar sua chamada se você tentar verificar o ID Apple de um usuário mais de uma vez por dia.

Parâmetros:
client_id: string de id do pacote do cliente, que é pública para tokens de autorização e atualização e deve ser passada.
client_secret: a string de assinatura JWT gerada na etapa anterior, que é pública para tokens de autorização e atualização e deve ser passada.
code: O código de autorização passado pelo cliente, dedicado para autorização, uso único e válido por 5 minutos.
grant_type: tipo de interação cliente-servidor, string fixa, comum para tokens de autorização e atualização, deve ser passado. Autorize a passar "código_de_ autorização", atualize o Token com "atualizar_token"
refresh_token: o token usado para atualizar o token, usado ao atualizar o token.
redirect_uri: o URL de redirecionamento usado para autorização, que é usado quando a web faz login com AppleID. Se você estiver usando a web, preencha a Configuração de autenticação da web ao configurar o login com appleid no site do desenvolvedor, e não é necessário transmiti-lo nativamente.

Dados retornados pelo histórico da 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 o cabeçalho e a carga em id_token para obter as informações correspondentes:

 

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
}

Ao comparar o usuário enviado do cliente com o sub na carga útil, você pode determinar se é um usuário unificado

5.4. A verificação é aprovada e o status de vinculação ou registro é retornado

Se tiver sido vinculado, ele retornará sessionId e userId.
Se não tiver sido vinculado, ele retornará informações semelhantes às exigidas para o login do WeChat e o cliente executará a operação de vinculação.



Autor: yuyangkk
link: https: //www.jianshu.com/p/12aade4d053b
Fonte: Os livros de Jane
são de propriedade do autor. Para reimpressões comerciais, entre em contato com o autor para autorização. Para reimpressões não comerciais, indique a fonte.

 

Acho que você gosta

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