Autenticação personalizada com o Couchbase Mobile
O Couchbase Mobile estende o Couchbase para a borda, gerenciando e sincronizando com segurança os dados de qualquer nuvem para todos os dispositivos móveis. O Couchbase Mobile apresenta um banco de dados incorporado - Couchbase Lite - com SQL e pesquisa de texto completo para JSON, sincronização ponto a ponto incorporada e segurança de ponta a ponta, da nuvem à borda.
O Couchbase Mobile também apresenta um gateway seguro da Web, o Sync Gateway, que permite o acesso e a sincronização de dados pela Web e oferece suporte a vários métodos de autenticação. Um desses métodos é a autenticação personalizada, em que um App Server lida com a autenticação em um sistema externo.
Esta publicação do blog o guiará pelo fluxo de autenticação personalizada com exemplos de como implementar o código do App Server e o código do aplicativo móvel. Uma OpenLDAP é usado neste exemplo, mas o fluxo se aplica a qualquer provedor de autenticação externo.
O exemplo do App Server é um aplicativo node.js simples e as amostras de código do aplicativo móvel usam o SDK do Couchbase Lite para Android.
Pré-requisitos
Este blog pressupõe familiaridade com o Couchbase Server, o Sync Gateway e o Couchbase Lite.
Você precisará de uma instalação operacional do Sync Gateway 2.5 e do Couchbase Server EE 6.x. Se necessário, os links a seguir podem ajudá-lo a começar a trabalhar rapidamente:
Todo o código deste blog está disponível no seguinte repositório Git: https://github.com/dugbonsai/sg-custom-auth
Fluxo de autenticação personalizado
O diagrama a seguir mostra um exemplo de autenticação personalizada.

- O usuário do aplicativo móvel tenta fazer login com suas credenciais por meio de uma interface REST exposta pelo App Server.
- O App Server autentica o usuário em um servidor OpenLDAP.
- Se o usuário não estiver autenticado, ele retornará à interface de login.
- Se o usuário for autenticado, o App Server obterá as informações do usuário do Sync Gateway por meio de uma interface REST.
- Se o usuário já existir no Sync Gateway, vá para a etapa 8.
- Se o usuário não existir no Sync Gateway, o App Server criará um novo usuário no Sync Gateway por meio de uma interface REST.
- Se o usuário não tiver sido criado no Sync Gateway, o App Server retornará um erro e o usuário retornará à interface de login.
- Se o usuário tiver sido criado no Sync Gateway, o App Server criará uma nova sessão para o usuário no Sync Gateway por meio de uma interface REST.
- Se a sessão não tiver sido criada no Sync Gateway, o App Server retornará um erro e o usuário retornará à interface de login.
- Se a sessão tiver sido criada no Sync Gateway, o App Server retornará a ID da sessão.
- O aplicativo móvel armazena o ID da sessão e cria um replicador do Couchbase Lite usando o ID da sessão.
- Se a replicação falhar devido a uma sessão expirada no Sync Gateway, o usuário retornará à interface de login.
Configuração do OpenLDAP
Se já tiver um servidor LDAP configurado, pule esta seção. Se você não tiver um servidor LDAP configurado, Estas instruções o orientarão na configuração do OpenLDAP no Ubuntu 18.04.
- Criar um arquivo LDIF (ldap_data.ldif) com informações para preencher o banco de dados LDAP (Clique aqui para obter mais detalhes sobre os arquivos LDIF). As instruções para configurar o OpenLDAP acima também contêm instruções para criar o arquivo LDIF para preencher o banco de dados LDAP. Neste exemplo, o usuário mobileuser (a partir da linha 13) será usado na autenticação do aplicativo móvel.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
dn: ou=Pessoas,dc=exemplo,dc=com objectClass: organizationalUnit ou: Pessoas dn: ou=Grupos,dc=exemplo,dc=com objectClass: organizationalUnit ou: Grupos dn: cn=departamento,ou=Grupos,dc=exemplo,dc=com objectClass: posixGroup cn: subgrupo gidNumber: 5000 dn: uid=usuário móvel,ou=Pessoas,dc=exemplo,dc=com objectClass: inetOrgPerson objectClass: posixAccount objectClass: shadowAccount uid: usuário móvel sn: Usuário givenName: Celular cn: Celular Usuário displayName: usuário móvel uidNumber: 10000 gidNumber: 5000 userPassword: senha gecos: Celular Usuário loginShell: /caixa/bash homeDirectory: /casa/usuário móvel |
- Adicione os dados iniciais ao banco de dados OpenLDAP:
|
1 |
$ ldapadd -x -D cn=administrador,dc=exemplo,dc=com -W -f ldap_data.ldif |
- Teste a configuração procurando por mobileuser no diretório OpenLDAP:
|
1 |
$ ldapsearch -x -LLL -b dc=exemplo,dc=com 'uid=mobileuser' |
Você verá as informações do usuário móvel:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
dn: uid=usuário móvel,ou=Pessoas,dc=exemplo,dc=com objectClass: inetOrgPerson objectClass: posixAccount objectClass: shadowAccount uid: usuário móvel sn: Usuário givenName: Celular cn: Celular Usuário displayName: usuário móvel uidNumber: 10000 gidNumber: 5000 gecos: Celular Usuário loginShell: /caixa/bash homeDirectory: /casa/usuário móvel |
Implementação do servidor de aplicativos
O App Server é implementado como um aplicativo node.js. O código completo do App Server está disponível em auth.js no seguinte repositório Git: sg-custom-auth. O App Server usa o pacote passport-ldapauth para autenticação LDAP. Os trechos de código a seguir destacam a chamada para autenticação no servidor OpenLDAP e as chamadas da API REST do Sync Gateway.
O App Server deve tratar as chamadas para POST /login. Esse endpoint é chamado a partir do aplicativo móvel com as credenciais de usuário armazenadas no corpo da solicitação em nome de usuário e senha. O App Server usa essas credenciais para se autenticar no servidor OpenLDAP.
O valor de searchBase deve corresponder aos componentes de domínio definidos em seu servidor LDAP. dc=example,dc=com foi usado acima, portanto, os mesmos valores são usados aqui (linha 12).
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
var expresso = exigir("expresso), passaporte = exigir("passaporte), bodyParser = exigir('body-parser'), Estratégia de Ldap = exigir('passport-ldapauth'), enrolar = exigir('curl-request'); var syncGatewayEndpoint = 'https://:4985/'; var aplicativo = expresso(); var OPTS = { servidor: { url: 'ldap://:389', searchBase: 'dc=example,dc=com', // DEVE corresponder ao diretório LDAP filtro de pesquisa: '(uid={{username}})' } }; passaporte.uso(novo Estratégia de Ldap(OPTS)); aplicativo.uso(bodyParser.json()); aplicativo.uso(bodyParser.codificado por url({estendido: falso})); aplicativo.uso(passaporte.inicializar()); aplicativo.postagem('/login', passaporte.autenticar('ldapauth', {sessão: falso}), função(req, res) { // usuário autenticado com sucesso no LDAP } |
As etapas a seguir serão executadas se o usuário for autenticado.
Obter informações do usuário do Sync Gateway
Obtenha informações do usuário do Sync Gateway chamando GET /{db}/_user/{name}. Se o usuário existir no Sync Gateway, o código de resposta será 200. Se o usuário não existir no Sync Gateway, o código de resposta será 404.
|
1 2 3 4 5 6 7 8 9 10 |
getUser = novo(enrolar); getUser.setHeaders(['Content-Type: application/json']) .obter(syncGatewayEndpoint + '/_user/' + req.corpo.nome de usuário) .então(({statusCode, corpo, cabeçalhos}) => { se (statusCode == 404) { // status == 404: o usuário não existe } mais se (statusCode == 200) { // status == 200: o usuário existe } }) |
Se o usuário não existir no Sync Gateway, crie um novo usuário
Crie um novo usuário no Sync Gateway chamando POST /{db}/_user/. Se o usuário tiver sido criado com êxito no gateway Sync, o código de resposta será 201.
|
1 2 3 4 5 6 7 8 9 10 11 |
postUser = novo(enrolar); postUser.setHeaders(['Content-Type: application/json']) .setBody('{"name": "' + req.corpo.nome de usuário + '", "password": "' + req.corpo.senha + '"}') .postagem(syncGatewayEndpoint + '/_user/') .então(({statusCode, corpo, cabeçalhos}) => { se (statusCode == 201) { // status == 201: sucesso } mais { // não foi possível criar o usuário } }) |
Criar uma sessão para o usuário no Sync Gateway
Crie uma sessão para o usuário no Sync Gateway chamando POST /{db}/_session. Neste exemplo, a sessão expirará após 30 minutos. Se a sessão tiver sido criada com êxito no Sync Gateway, o código de resposta será 200. A resposta JSON contém os seguintes valores:
session_idID da nova sessão: o ID da nova sessão. Isso será usado pelo aplicativo móvel para autenticação com o Sync Gateway.
expiraçõesData de expiração: registro de data e hora em que a sessão expira. Isso não é usado no aplicativo móvel.
nome_do_cookieNome do cookie de sessão. Não é usado no aplicativo móvel.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
resBody = {statusCode: 200}; postSession = novo(enrolar); postSession.setHeaders(['Content-Type: application/json']) .setBody('{"name": "' + solicitação.corpo.nome de usuário + '", "ttl": 1800}') .postagem(syncGatewayEndpoint + '/_session') .então(({statusCode, corpo, cabeçalhos}) => { se (statusCode == 200) { // status == 200: sucesso resBody.session_id = corpo.session_id; resBody.expirações = corpo.expirações; resBody.nome_do_cookie = corpo.nome_do_cookie; // enviar resposta de sucesso de volta ao cliente resposta.enviar(JSON.stringify(resBody)); } mais { // não foi possível criar a sessão } }) |
Teste de autenticação
Para testar a autenticação do App Server, inicie-o usando o seguinte comando:
|
1 |
$ nó autenticação.js |
Após a inicialização, você verá o seguinte:
|
1 |
Escuta em porto 8080 |
Você pode testar o servidor de aplicativos usando um comando curl simples, como segue (ou Postman, etc.):
|
1 |
$ enrolar -d "username=mobileuser&password=password" -X POST https://:8080/login |
Você verá uma saída semelhante à seguinte:
|
1 |
{"statusCode":200,"session_id":"c149012eaa8d0cf15b1b4110cf0a2fec259ef726","expira":"2019-08-01T13:47:56.311076773Z","cookie_name":"SyncGatewaySession"} |
Se o usuário não existir no LDAP, a resposta será:
|
1 |
Não autorizado |
A saída do App Server terá a seguinte aparência:
|
1 2 3 4 5 |
usuário móvel tem foram autenticado com LDAP criando usuário usuário móvel em Sincronização Gateway usuário usuário móvel criado em Sincronização Gateway criar sessão para usuário usuário móvel criado sessão para usuário móvel |
Implementação de aplicativos móveis
Tudo o que resta é fazer as chamadas apropriadas do aplicativo móvel para o App Server e o Sync Gateway. O aplicativo móvel usa o Estrutura de vôlei para fazer a chamada REST para o App Server. Os trechos de código a seguir destacam a chamada para o App Server e o código do Couchbase Lite para autenticar usando o session_id.
Autenticar o usuário móvel
Autenticar o usuário com o App Server chamando POST /login/
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
JSONObject reqBody = novo JSONObject(); reqBody.colocar("nome de usuário", <usuário fornecido nome de usuário>); reqBody.colocar("senha", <usuário fornecido senha>); Cordas url = <Aplicativo Servidor hospedeiro>:8080/login; Fila de solicitações fila = Vôlei.newRequestQueue(<contexto>); JsonRequest<JSONObject> jsonRequest = novo JsonObjectRequest( Solicitação.Método.POST, url, reqBody, novo Resposta.Ouvinte<JSONObject>() { @Substituir público vazio onResponse(JSONObject resposta) { // obter session_id da resposta tentar { Cordas ID da sessão = resposta.getString("session_id"); // Armazenar session_id } captura (JSONException je) { // Tratar a exceção } } }, novo Resposta.Listador de erros() { @Substituir público vazio onErrorResponse(VolleyError erro) { // falha na autenticação } }); fila.adicionar(jsonRequest); |
Criar uma replicação única
Crie uma replicação única usando o session_id salvo (linha 13) e autentique novamente se a sessão do Sync Gateway tiver expirado.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
Cordas syncGatewayEndpoint = "ws://:4984/{db}"; URI url = nulo; tentar { url = novo URI(mSyncGatewayEndpoint); } captura (URISyntaxException e) { e.printStackTrace(); retorno; } ReplicatorConfiguration configuração = novo ReplicatorConfiguration(banco de dados, novo URLEndpoint(url)); configuração.setReplicatorType(ReplicatorConfiguration.ReplicatorType.PUSH_AND_PULL); configuração.setContinuous(falso); configuração.setAuthenticator(novo SessionAuthenticator(ID da sessão)); Replicador replicador = novo Replicador(configuração); replicador.addChangeListener(novo ReplicatorChangeListener() { @Substituir público vazio alterado(ReplicatorChange mudança) { CouchbaseLiteException erro = mudança.getStatus().getError(); se (erro != nulo) { se (erro.getCode() == 10401) { // sessão expirou; autenticar novamente } } ... } }); replicador.iniciar(); |
O que vem a seguir
Se você é novo no Couchbase, aproveite nosso treinamento on-line gratuito disponível em https://learn.couchbase.com para saber mais.
Mais informações tutoriais para celular pode ser encontrado no site Página da Web dos tutoriais do Couchbase.