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=People,dc=example,dc=com objectClass: organizationalUnit ou: People dn: ou=Groups,dc=example,dc=com objectClass: organizationalUnit ou: Groups dn: cn=department,ou=Groups,dc=example,dc=com objectClass: posixGroup cn: subgroup gidNumber: 5000 dn: uid=mobileuser,ou=People,dc=example,dc=com objectClass: inetOrgPerson objectClass: posixAccount objectClass: shadowAccount uid: mobileuser sn: User givenName: Mobile cn: Mobile User displayName: mobileuser uidNumber: 10000 gidNumber: 5000 userPassword: password gecos: Mobile User loginShell: /bin/bash homeDirectory: /home/mobileuser |
- Adicione os dados iniciais ao banco de dados OpenLDAP:
|
1 |
$ ldapadd -x -D cn=admin,dc=example,dc=com -W -f ldap_data.ldif |
- Teste a configuração procurando por mobileuser no diretório OpenLDAP:
|
1 |
$ ldapsearch -x -LLL -b dc=example,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=mobileuser,ou=People,dc=example,dc=com objectClass: inetOrgPerson objectClass: posixAccount objectClass: shadowAccount uid: mobileuser sn: User givenName: Mobile cn: Mobile User displayName: mobileuser uidNumber: 10000 gidNumber: 5000 gecos: Mobile User loginShell: /bin/bash homeDirectory: /home/mobileuser |
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 express = require('express'), passport = require('passport'), bodyParser = require('body-parser'), LdapStrategy = require('passport-ldapauth'), curl = require('curl-request'); var syncGatewayEndpoint = 'https://<Sync Gateway Host>:4985/<db>'; var app = express(); var OPTS = { server: { url: 'ldap://<OpenLDAP Host>:389', searchBase: 'dc=example,dc=com', // MUST match LDAP directory searchFilter: '(uid={{username}})' } }; passport.use(new LdapStrategy(OPTS)); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({extended: false})); app.use(passport.initialize()); app.post('/login', passport.authenticate('ldapauth', {session: false}), function(req, res) { // user successfully authenticated against 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 = new(curl); getUser.setHeaders(['Content-Type: application/json']) .get(syncGatewayEndpoint + '/_user/' + req.body.username) .then(({statusCode, body, headers}) => { if (statusCode == 404) { // status == 404: user does not exist } else if (statusCode == 200) { // status == 200: user exists } }) |
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 = new(curl); postUser.setHeaders(['Content-Type: application/json']) .setBody('{"name": "' + req.body.username + '","password": "' + req.body.password + '"}') .post(syncGatewayEndpoint + '/_user/') .then(({statusCode, body, headers}) => { if (statusCode == 201) { // status == 201: success } else { // user could not be created } }) |
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 = new(curl); postSession.setHeaders(['Content-Type: application/json']) .setBody('{"name": "' + request.body.username + '","ttl": 1800}') .post(syncGatewayEndpoint + '/_session') .then(({statusCode, body, headers}) => { if (statusCode == 200) { // status == 200: success resBody.session_id = body.session_id; resBody.expires = body.expires; resBody.cookie_name = body.cookie_name; // send success response back to client response.send(JSON.stringify(resBody)); } else { // session could not be created } }) |
Teste de autenticação
Para testar a autenticação do App Server, inicie-o usando o seguinte comando:
|
1 |
$ node auth.js |
Após a inicialização, você verá o seguinte:
|
1 |
Listening on port 8080 |
Você pode testar o servidor de aplicativos usando um comando curl simples, como segue (ou Postman, etc.):
|
1 |
$ curl -d "username=mobileuser&password=password" -X POST https://<AppServer host>:8080/login |
Você verá uma saída semelhante à seguinte:
|
1 |
{"statusCode":200,"session_id":"c149012eaa8d0cf15b1b4110cf0a2fec259ef726","expires":"2019-08-01T13:47:56.311076773Z","cookie_name":"SyncGatewaySession"} |
Se o usuário não existir no LDAP, a resposta será:
|
1 |
Unauthorized |
A saída do App Server terá a seguinte aparência:
|
1 2 3 4 5 |
mobileuser has been authenticated with LDAP creating user mobileuser in Sync Gateway user mobileuser created in Sync Gateway create session for user mobileuser created session for mobileuser |
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 = new JSONObject(); reqBody.put("username", <user supplied username>); reqBody.put("password", <user supplied password>); String url = <App Server host>:8080/login; RequestQueue queue = Volley.newRequestQueue(<context>); JsonRequest<JSONObject> jsonRequest = new JsonObjectRequest( Request.Method.POST, url, reqBody, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { // get session_id from response try { String sessionID = response.getString("session_id"); // Store session_id } catch (JSONException je) { // Handle exception } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { // authentication failed } }); queue.add(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 |
String syncGatewayEndpoint = "ws://<Sync Gateway Host>:4984/{db}"; URI url = null; try { url = new URI(mSyncGatewayEndpoint); } catch (URISyntaxException e) { e.printStackTrace(); return; } ReplicatorConfiguration config = new ReplicatorConfiguration(database, new URLEndpoint(url)); config.setReplicatorType(ReplicatorConfiguration.ReplicatorType.PUSH_AND_PULL); config.setContinuous(false); config.setAuthenticator(new SessionAuthenticator(sessionID)); Replicator replicator = new Replicator(config); replicator.addChangeListener(new ReplicatorChangeListener() { @Override public void changed(ReplicatorChange change) { CouchbaseLiteException error = change.getStatus().getError(); if (error != null) { if (error.getCode() == 10401) { // session expired; re-authenticate } } ... } }); replicator.start(); |
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.