{"id":1985,"date":"2015-10-23T08:04:41","date_gmt":"2015-10-23T08:04:40","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=1985"},"modified":"2025-06-13T19:58:53","modified_gmt":"2025-06-14T02:58:53","slug":"couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/pt\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/","title":{"rendered":"Couchbase LIVE Nova York:  Couchbase Mobile 102 - Como adicionar sincroniza\u00e7\u00e3o segura aos seus aplicativos m\u00f3veis"},"content":{"rendered":"<p style=\"text-align: center;\"><a href=\"https:\/\/bit.ly\/CBNYC2015\"><img decoding=\"async\" src=\"\/wp-content\/original-assets\/2015\/october\/couchbase-live-new-york-couchbase-mobile-102---how-to-add-secure-sync-to-your-mobile-applications\/events.cbliveny.bannerheader.lockup.png\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">Da sess\u00e3o 102 no <a href=\"https:\/\/bit.ly\/couchbaseNYC01\">Couchbase LIVE New York pista m\u00f3vel<\/a>Em seguida, continuamos a iterar no aplicativo de amostra do Couchbase Mobile que foi descrito no c\u00f3digo do <a href=\"https:\/\/bit.ly\/CBNYC2015_101\">Sess\u00e3o \"Couchbase Mobile 101: Como criar seu primeiro aplicativo m\u00f3vel\".<\/a><\/p>\n<p style=\"text-align: justify;\">Na sess\u00e3o Couchbase Mobile 102, exploramos <a href=\"https:\/\/bit.ly\/sync_gateway\">Gateway de sincroniza\u00e7\u00e3o<\/a> em detalhes sobre seus recursos e sobre \"Como adicionar sincroniza\u00e7\u00e3o segura a seus aplicativos m\u00f3veis\", protegendo o aplicativo de amostra Grocery Sync, que pode ser encontrado no reposit\u00f3rio do Github para <a href=\"https:\/\/github.com\/couchbaselabs\/Grocery-Sync-iOS\">iOS<\/a> e <a href=\"https:\/\/github.com\/couchbaselabs\/GrocerySync-Android\">Android<\/a>.  Neste blog, abordaremos o que foi discutido sobre o Sync Gateway, que \u00e9 o componente que une o Couchbase Lite e o Couchbase Server; voc\u00ea pode <a href=\"https:\/\/www.slideshare.net\/Couchbase\/couchbase-mobile-102-couchbase-live-new-york-2015\">refer\u00eancia aos slides<\/a> sobre o t\u00f3pico e os trechos de c\u00f3digo descritos a seguir.<\/p>\n<p style=\"text-align: justify;\"><strong>Principais preocupa\u00e7\u00f5es com a seguran\u00e7a de dados m\u00f3veis<\/strong><\/p>\n<p style=\"text-align: justify;\">Uma \u00e1rea que o Sync Gateway ajuda a resolver \u00e9 a replica\u00e7\u00e3o de dados, que diz respeito \u00e0 forma como os dados s\u00e3o sincronizados entre a nuvem e o aplicativo m\u00f3vel no dispositivo.  A autentica\u00e7\u00e3o dos seus usu\u00e1rios antes que a replica\u00e7\u00e3o possa ocorrer \u00e9 outra \u00e1rea importante que o Sync Gateway aborda e sobre a qual ocorre o particionamento de dados.  Quando a replica\u00e7\u00e3o estiver em vigor, os dados precisar\u00e3o ser particionados de acordo com os usu\u00e1rios para determinar onde os dados espec\u00edficos ser\u00e3o distribu\u00eddos.  Al\u00e9m disso, h\u00e1 o controle de acesso aos dados, no qual, se um usu\u00e1rio tiver sido autenticado, o Sync Gateway poder\u00e1 ajudar a configurar as permiss\u00f5es de leitura e grava\u00e7\u00e3o adequadamente.  Vamos explorar cada um desses aspectos em mais detalhes.<\/p>\n<p style=\"text-align: justify;\"><strong>[1] Autentica\u00e7\u00e3o do usu\u00e1rio<\/strong><\/p>\n<p style=\"text-align: justify;\">Com o modelo de autentica\u00e7\u00e3o conect\u00e1vel suportado pelo Couchbase Mobile, h\u00e1 uma variedade de maneiras de implementar a autentica\u00e7\u00e3o em que o Sync Gateway permite configura\u00e7\u00f5es personalizadas para a estrutura de seguran\u00e7a da arquitetura do aplicativo.  O Sync Gateway oferece suporte a tr\u00eas provedores p\u00fablicos com modelos de autentica\u00e7\u00e3o \"Basic Auth\", \"Facebook\" e \"Persona<b>.<\/b><\/p>\n<div style=\"font-family: 'Helvetica Neue'; font-size: 14px;\"><b>Autentica\u00e7\u00e3o do Facebook:  Configura\u00e7\u00e3o do gateway de sincroniza\u00e7\u00e3o<\/b><\/div>\n<div style=\"font-family: 'Helvetica Neue'; font-size: 14px;\">\n<div>O trecho de c\u00f3digo abaixo ilustra como configurar o Facebook para o Sync Gateway.<\/div>\n<pre><code class=\"language-javascript\">\r\n{\r\n    \"facebook\" : { \"register\" : false },\r\n    \"databases\": {\r\n        \"grocery-sync\": {\r\n            \u201cserver\u201d:\u201dhttps:\/\/cbserver:8091\u201d,\r\n            \u201cbucket\":\"grocery-sync\",\r\n            \"users\": {\"GUEST\": {\"disabled\": true}},\r\n            \"sync\":`function(doc) {channel(doc.channels);}`\r\n        }\r\n    }\r\n}\r\n<\/code><\/pre>\n<div>No arquivo de configura\u00e7\u00e3o, definimos que queremos usar o Facebook como provedor de autentica\u00e7\u00e3o.  Al\u00e9m desse ponto, o Sync Gateway far\u00e1 o trabalho de comunica\u00e7\u00e3o com o Facebook para autenticar o token para os clientes.<\/div>\n<\/div>\n<div style=\"font-family: 'Helvetica Neue'; font-size: 14px;\">\n<div><b>Autentica\u00e7\u00e3o de provedores personalizados:  Caminho de comunica\u00e7\u00e3o \u00a0\u00a0 <\/b><\/div>\n<div><\/div>\n<div style=\"text-align: justify;\">Para implementar um provedor personalizado em que existe uma base de usu\u00e1rios em uma configura\u00e7\u00e3o de servidor LDAP, o aplicativo m\u00f3vel aponta primeiro para o aplicativo ou servidor de autentica\u00e7\u00e3o.  O servidor de autentica\u00e7\u00e3o \u00e9, ent\u00e3o, respons\u00e1vel pela autentica\u00e7\u00e3o dos usu\u00e1rios e, depois de autenticar um usu\u00e1rio com \u00eaxito, o servidor de autentica\u00e7\u00e3o faria uma chamada de API para a API de administra\u00e7\u00e3o do Sync Gateway na segunda etapa para obter uma sess\u00e3o v\u00e1lida para esse usu\u00e1rio.  Esse token de sess\u00e3o \u00e9 ent\u00e3o roteado de volta para o servidor de autentica\u00e7\u00e3o e, em seguida, devolvido ao cliente m\u00f3vel.  A terceira e \u00faltima etapa, depois que o aplicativo m\u00f3vel obt\u00e9m o token, \u00e9 a comunica\u00e7\u00e3o direta com o Sync Gateway usando o token de sess\u00e3o para obter todos os dados necess\u00e1rios para o usu\u00e1rio no dispositivo.<\/div>\n<div style=\"text-align: justify;\"><\/div>\n<div><strong>[2] Acesso de leitura e grava\u00e7\u00e3o de dados<\/strong><\/div>\n<\/div>\n<p style=\"text-align: justify;\">Muitas das quest\u00f5es de seguran\u00e7a est\u00e3o na forma de como gerenciamos o acesso de leitura e grava\u00e7\u00e3o.  O Sync Gateway permite definir pol\u00edticas de seguran\u00e7a de granula\u00e7\u00e3o fina para pol\u00edticas de leitura no n\u00edvel do documento e, em seguida, definir as pol\u00edticas de grava\u00e7\u00e3o at\u00e9 o n\u00edvel do campo.  A estrutura geral de aplica\u00e7\u00e3o de pol\u00edticas baseia-se em uma fun\u00e7\u00e3o Javascript Sync, na qual \u00e9 flex\u00edvel definir regras de seguran\u00e7a complexas para estender o aplicativo m\u00f3vel que executa o Couchbase Lite.<\/p>\n<p style=\"text-align: justify;\"><strong>Fun\u00e7\u00e3o de sincroniza\u00e7\u00e3o:  Configura\u00e7\u00e3o do gateway de sincroniza\u00e7\u00e3o<\/strong><\/p>\n<p style=\"text-align: justify;\">A fun\u00e7\u00e3o Sync \u00e9 o n\u00facleo do Sync Gateway para gerenciar o acesso de leitura e grava\u00e7\u00e3o e \u00e9 onde a maioria das regras de acesso aos dados \u00e9 definida.  Portanto, \u00e9 realmente o n\u00facleo de sua implementa\u00e7\u00e3o de seguran\u00e7a, em que a fun\u00e7\u00e3o Sync \u00e9 uma fun\u00e7\u00e3o JavaScript que \u00e9 executada sempre que qualquer documento JSON \u00e9 gravado no Sync Gateway.<\/p>\n<pre><code class=\"language-javascript\">{\r\n    \"databases\": {\r\n        \"grocery-sync\": {\r\n            \u201cserver\u201d:\"https:\/\/walrus:\",\r\n            \u201cbucket\":\"grocery-sync\",\r\n            \"users\": {\"GUEST\": {\"disabled\": true}},\r\n            \u201csync\u201d:`function(doc,oldDoc) {\r\n                channel(doc.channels);  }`\r\n        }\r\n    }\r\n}\r\n<\/code><\/pre>\n<p style=\"text-align: justify;\">A fun\u00e7\u00e3o \u00e9 definida no arquivo de configura\u00e7\u00e3o do Sync Gateway, no qual as assinaturas do m\u00e9todo recebem a revis\u00e3o atual do documento, doc, e a revis\u00e3o anterior, oldDoc.  O corpo do m\u00e9todo \u00e9 onde as regras de seguran\u00e7a s\u00e3o definidas com base nessas duas entradas.  \u00c9 aqui que uma fun\u00e7\u00e3o de sincroniza\u00e7\u00e3o b\u00e1sica simples pode ser definida primeiro e, em seguida, regras de seguran\u00e7a lentamente mais avan\u00e7adas podem ser criadas para cobrir todos os casos.  Com essa abordagem, podemos modificar a fun\u00e7\u00e3o de sincroniza\u00e7\u00e3o \u00e0 medida que novos tipos de documentos forem definidos ou se houver altera\u00e7\u00f5es no esquema JSON.<\/p>\n<p style=\"text-align: justify;\"><strong>Fun\u00e7\u00e3o de sincroniza\u00e7\u00e3o:  Permiss\u00e3o de grava\u00e7\u00e3o<\/strong><\/p>\n<div style=\"font-family: 'Helvetica Neue'; font-size: 14px;\">Com a seguran\u00e7a do lado da grava\u00e7\u00e3o, podemos determinar se um determinado documento proveniente de um usu\u00e1rio conhecido pode ou n\u00e3o ser gravado no armazenamento de back-end.  Para o gateway de sincroniza\u00e7\u00e3o, h\u00e1 quatro m\u00e9todos principais na fun\u00e7\u00e3o de sincroniza\u00e7\u00e3o a serem usados para permiss\u00f5es de grava\u00e7\u00e3o:<\/div>\n<div style=\"font-family: 'Helvetica Neue'; font-size: 14px;\">\n<ol>\n<li><strong>requireUser()<\/strong>:  Recebe como entrada uma lista de IDs de usu\u00e1rio e valida se os usu\u00e1rios ativos no momento fazem parte dessa lista<\/li>\n<li><strong>requireRole()<\/strong>:  Recebe como entrada uma lista de fun\u00e7\u00f5es, onde podemos ver se o requireUser recebeu essa fun\u00e7\u00e3o espec\u00edfica. Se n\u00e3o tiver, o documento ser\u00e1 rejeitado.<\/li>\n<li><strong>requireAccess()<\/strong>:  Recebe como entrada uma lista de canais, na qual \u00e9 obtida uma lista de usu\u00e1rios atuais e sua lista de canais para verificar se lhes foi concedido um determinado canal.  Se o usu\u00e1rio n\u00e3o fizer parte da lista, ele ser\u00e1 rejeitado.<\/li>\n<li><strong>lan\u00e7ar()<\/strong>:  O lan\u00e7amento permite que voc\u00ea fa\u00e7a qualquer inspe\u00e7\u00e3o que desejar no documento de entrada. Voc\u00ea pode ter uma valida\u00e7\u00e3o e dizer, por exemplo, se um documento \u00e9 do tipo \"item\" e se o tipo n\u00e3o corresponder, voc\u00ea pode rejeitar o documento.  Da mesma forma, voc\u00ea pode ter uma valida\u00e7\u00e3o baseada em um valor que esteja dentro de um determinado intervalo.  Portanto, a valida\u00e7\u00e3o de tipo em n\u00edvel de campo muito granular que pode ser implementada na Sync Function pode ser usada com um m\u00e9todo throw() nos documentos que n\u00e3o atendem a esses crit\u00e9rios.  Com throw(), voc\u00ea tamb\u00e9m pode fornecer detalhes do erro sobre o motivo pelo qual ele \u00e9 lan\u00e7ado e o motivo pelo qual os documentos s\u00e3o rejeitados.<\/li>\n<\/ol>\n<\/div>\n<p style=\"text-align: justify;\"><strong>Fun\u00e7\u00e3o de sincroniza\u00e7\u00e3o:  Permiss\u00e3o de leitura <\/strong><\/p>\n<div style=\"font-family: 'Helvetica Neue'; font-size: 14px;\">Com a seguran\u00e7a do lado da leitura, podemos usar \"Canais\" para o particionamento de dados por meio do uso da primitiva \"channel()\" para documentos, enquanto os usu\u00e1rios s\u00e3o atribu\u00eddos a diferentes canais usando a primitiva \"access()\".  O conceito aqui \u00e9 que cada documento \u00e9 associado a um conjunto de um ou mais canais e que cada fun\u00e7\u00e3o de usu\u00e1rio tem um conjunto de canais que pode ler.<\/div>\n<div style=\"font-family: 'Helvetica Neue'; font-size: 14px;\"><img loading=\"lazy\" decoding=\"async\" src=\"\/wp-content\/original-assets\/2015\/october\/couchbase-live-new-york-couchbase-mobile-102---how-to-add-secure-sync-to-your-mobile-applications\/channels.png\" width=\"554\" height=\"392\" \/><\/div>\n<p style=\"text-align: justify;\">Um canal espec\u00edfico passar\u00e1 a existir assim que o comando channel for usado para atribuir um usu\u00e1rio a um canal.  Nesse momento, o usu\u00e1rio procurar\u00e1 documentos marcados com o mesmo nome de canal.  Existem dois canais especiais com os par\u00e2metros estrela [*] e exclama\u00e7\u00e3o [!].<\/p>\n<ol>\n<li style=\"text-align: justify;\">Estrela[*]:  O canal * Star \u00e9 o canal em que todos os documentos s\u00e3o adicionados automaticamente a esse canal.  Um exemplo \u00e9 quando um usu\u00e1rio convidado recebe o canal *estrela, ele ter\u00e1 acesso ilimitado a todos os documentos.  Um caso de uso claro para esse atributo de canal seria semelhante aos privil\u00e9gios de administrador, em que qualquer usu\u00e1rio que tenha a * estrela em seu canal poder\u00e1 ver tudo no sistema.<\/li>\n<li style=\"text-align: justify;\">Exclama\u00e7\u00e3o[!]:  O segundo canal especial \u00e9 o atributo ! exclamation, que \u00e9 usado para descrever o canal p\u00fablico que \u00e9 focado na perspectiva do documento, em que, se voc\u00ea adicionar um documento ao canal p\u00fablico, todos os usu\u00e1rios poder\u00e3o ver esse documento espec\u00edfico.  Um caso de uso claro para esse atributo de canal seria semelhante a ter um documento para an\u00fancios p\u00fablicos ou transmitir uma mensagem para todos os usu\u00e1rios.<\/li>\n<\/ol>\n<p style=\"text-align: justify;\"><strong>Fun\u00e7\u00e3o de sincroniza\u00e7\u00e3o:  Por exemplo<\/strong><\/p>\n<p style=\"text-align: justify;\">No exemplo a seguir, exploraremos <span style=\"font-family: 'Helvetica Neue'; font-size: 14px;\">usando os recursos descritos acima em <\/span>como proteger o <span style=\"font-family: 'Helvetica Neue'; font-size: 14px;\">Grocery Sync Application da sess\u00e3o Couchbase Mobile 101, onde ele existe como um <\/span>aplicativo totalmente inseguro e sem privacidade.  Ao interagir com o Sync Gateway, os usu\u00e1rios acabar\u00e3o vendo apenas seus pr\u00f3prios itens, em vez de ver a mesma lista com todos os itens dispon\u00edveis que s\u00e3o adicionados.<\/p>\n<pre><code class=\"language-javascript\">{\r\n    \"log\" : [\u201c*\u201d],\r\n    \"databases\": {\r\n        \"grocery-sync\": {\r\n            \u201cserver\u201d:\u201dwalrus:\u201d,\r\n            \u201cbucket\":\"grocery-sync\",\r\n            \"users\": {\r\n    \"GUEST\": {\r\n  \"disabled\": false,\r\n  \u201cadmin_channels\u201d : [\u201c*\u201d] }\r\n             }\r\n         }\r\n      }\r\n }\r\n<\/code><\/pre>\n<div>O arquivo de configura\u00e7\u00e3o inicial do Sync Gateway \u00e9 onde nada est\u00e1 ativado e \u00e9 a configura\u00e7\u00e3o padr\u00e3o que vem com o aplicativo Grocery Sync.  Tamb\u00e9m ativamos o usu\u00e1rio convidado para que ele tenha acesso a todos os canais, o que significa que veremos todos os documentos e novos itens que forem adicionados.  O primeiro passo para adicionar seguran\u00e7a \u00e9 ter usu\u00e1rios para autenticar, que \u00e9 o que implementaremos a seguir.<\/div>\n<pre><code class=\"language-javascript\">{\r\n    \u201dlog\" : [\u201c*\u201d],\r\n    \"databases\": {\r\n        \"grocery-sync\": {\r\n            \u201cserver\u201d:\u201dwalrus:\u201d,\r\n            \u201cbucket\":\"grocery-sync\",\r\n            \"users\": {\r\n      \u201calice\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201c*\u201d] },\r\n     \u201cbob\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201c*\u201d] }\r\n            }\r\n      }\r\n }\r\n<\/code><\/pre>\n<div>A ideia \u00e9 identificar usu\u00e1rios individuais que fazem parte do aplicativo e usar isso como uma medida de seguran\u00e7a dentro do aplicativo.  A atualiza\u00e7\u00e3o do arquivo de configura\u00e7\u00e3o est\u00e1 criando os usu\u00e1rios Alice e Bob.  Removemos a conta de Convidado e usamos a Autentica\u00e7\u00e3o b\u00e1sica pr\u00e9-definindo dois usu\u00e1rios, sendo que inicialmente os usu\u00e1rios t\u00eam acesso a todos os canais.  Agora, com os usu\u00e1rios criados, queremos criar uma fun\u00e7\u00e3o de sincroniza\u00e7\u00e3o personalizada para permitir a defini\u00e7\u00e3o da l\u00f3gica de seguran\u00e7a de leitura e grava\u00e7\u00e3o para os usu\u00e1rios no aplicativo.<\/div>\n<pre><code class=\"language-javascript\">{\r\n    \u201dlog\" : [\u201c*\u201d],\r\n    \"databases\": {\r\n        \"grocery-sync\": {\r\n            \u201cserver\u201d:\u201dwalrus:\u201d,\r\n            \u201cbucket\":\"grocery-sync\",\r\n            \"users\": {\r\n      \u201calice\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201c*\u201d] },\r\n     \u201cbob\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201c*\u201d] }\r\n            },\r\n \u201csync\u201d : \u2018\r\n    function(doc, oldDoc) {\r\n      \/\/Add placeholder sync function, add custom read\/write logic here \r\n           }\u2018\r\n  }\r\n      }\r\n}\r\n<\/code><\/pre>\n<div><span style=\"font-family: 'Helvetica Neue'; font-size: 14px;\">Agora adicionamos uma fun\u00e7\u00e3o de sincroniza\u00e7\u00e3o de espa\u00e7o reservado e \u00e9 aqui que nos concentraremos e continuaremos a iterar na l\u00f3gica para fornecer controle de acesso aos usu\u00e1rios sobre os dados no sistema.  Em seguida, protegeremos ainda mais os canais fornecendo nomes de canais espec\u00edficos.\u00a0 <\/span><\/div>\n<pre><code class=\"language-javascript\">{\r\n    \u201dlog\" : [\u201c*\u201d],\r\n    \"databases\": {\r\n        \"grocery-sync\": {\r\n            \u201cserver\u201d:\u201dwalrus:\u201d,\r\n            \u201cbucket\":\"grocery-sync\",\r\n            \"users\": {\r\n      \u201calice\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201citems-alice\u201d]  },\r\n     \u201cbob\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201citems-bob\u201d] }\r\n            },\r\n \u201csync\u201d : \u2018\r\n    function(doc, oldDoc) {\r\n \/\/Add placeholder sync function, add custom read\/write logic here \r\n            }\r\n           \u2018\r\n    }\r\n          }\r\n    }\r\n<\/code><\/pre>\n<div>Agora, daremos aos usu\u00e1rios acesso ao seu pr\u00f3prio canal de itens na configura\u00e7\u00e3o do sync-gateway, removendo a estrela [\"*\"] do canal de administra\u00e7\u00e3o e adicionando um novo canal privado espec\u00edfico para o usu\u00e1rio, como no caso aqui, \"items-alice\".  Anteriormente, com o canal [\"*\"], ele permitia que os usu\u00e1rios vissem todos os documentos no sistema e n\u00e3o queremos isso como medida de seguran\u00e7a.  Fazemos o mesmo para \"Bob\", configurando o canal \"admin_channels\" para ser espec\u00edfico para \"items-bob\".  Ao fazer isso, teremos itens acess\u00edveis somente aos seus propriet\u00e1rios, portanto, precisamos vincular o campo do propriet\u00e1rio em um documento de item de mercearia ao canal de itens pessoais do propriet\u00e1rio.  Em seguida, modificaremos ainda mais a fun\u00e7\u00e3o de sincroniza\u00e7\u00e3o para que isso ocorra.<\/div>\n<pre><code class=\"language-javascript\">{\r\n    \u201dlog\" : [\u201c*\u201d],\r\n    \"databases\": {\r\n        \"grocery-sync\": {\r\n            \u201cserver\u201d:\u201dwalrus:\u201d,\r\n            \u201cbucket\":\"grocery-sync\",\r\n            \"users\": {\r\n      \u201calice\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201citems-alice\u201d]  },\r\n     \u201cbob\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201citems-bob\u201d] }\r\n            },\r\n \u201csync\u201d : \u2018\r\n    function(doc, oldDoc) {\r\n     channel(\u201citems-\u201d+doc.owner);  }\r\n               \/\/Add item document to owner\u2019s items channel\r\n           \u2018\r\n    }\r\n          }\r\n    }\r\n<\/code><\/pre>\n<p style=\"text-align: justify;\">Quando um documento est\u00e1 sendo gravado no Sync Gateway, n\u00f3s o atribu\u00edmos a um canal em que o nome do canal tem o formato de \"itens\" - prefixado<b> <\/b>com o valor da propriedade do propriet\u00e1rio de dentro do documento do propriet\u00e1rio que \u00e9 obtido por \"doc.owner\".  A configura\u00e7\u00e3o anterior \u00e9 quando a propriedade do documento \u00e9 definida como \"bob\" e os \"itens\" s\u00e3o atribu\u00eddos ao canal \"items-bob\".  O usu\u00e1rio \"bob\" tem acesso ao canal \"items-bob\" e, basicamente, esse \u00e9 o canal ao qual Bob recebeu acesso em seu registro de usu\u00e1rio.  Agora, qualquer item que tenha o propriet\u00e1rio \"bob\" como propriedade ser\u00e1 visto por esse canal pelo pr\u00f3prio Bob, mas n\u00e3o ser\u00e1 visto por Alice porque n\u00e3o estar\u00e1 no canal \"items-alice\".  O que ocorreu na configura\u00e7\u00e3o foi que atribu\u00edmos um documento a um canal apropriado e tamb\u00e9m concedemos acesso ao propriet\u00e1rio de forma program\u00e1tica por meio do canal \"items-\" do propriet\u00e1rio.<\/p>\n<p style=\"text-align: justify;\">Portanto, agora os usu\u00e1rios s\u00f3 podem ver\/ler seus pr\u00f3prios itens e, efetivamente, suas pr\u00f3prias listas de compras.  Mas eles ainda podem escrever na lista um do outro, pois Bob pode carregar um item e definir a propriedade do propriet\u00e1rio como \"Alice\", o que, de fato, permite que Bob infrinja facilmente a lista de compras de Alice.  A pr\u00f3xima etapa para adicionar seguran\u00e7a \u00e9 garantir que, quando um documento for recebido, a propriedade do propriet\u00e1rio corresponda ao usu\u00e1rio autenticado atual.<\/p>\n<pre><code class=\"language-javascript\">{\r\n    \u201dlog\" : [\u201c*\u201d],\r\n    \"databases\": {\r\n        \"grocery-sync\": {\r\n            \u201cserver\u201d:\u201dwalrus:\u201d,\r\n            \u201cbucket\":\"grocery-sync\",\r\n            \"users\": {\r\n      \u201calice\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201citems-alice\u201d]  },\r\n     \u201cbob\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201citems-bob\u201d] }\r\n        },\r\n \u201csync\u201d : \u2018\r\n    function(doc, oldDoc) {\r\n        requireUser(doc.owner); \r\n        \/\/The owner of the item document must be the authenticated user\r\n        channel(\u201citems-\u201d+doc.owner);  }\r\n                         \u2018\r\n    }\r\n    }\r\n}\r\n<\/code><\/pre>\n<div style=\"text-align: justify;\">A configura\u00e7\u00e3o atualizada agora cont\u00e9m a fun\u00e7\u00e3o 'requireUser' no in\u00edcio da fun\u00e7\u00e3o de sincroniza\u00e7\u00e3o com um par\u00e2metro de entrada sendo a propriedade do propriet\u00e1rio que \u00e9 obtida por meio de 'doc.owner' de dentro do documento.  Basicamente, o usu\u00e1rio autenticado atual que est\u00e1 tentando carregar esse documento deve ter um ID de usu\u00e1rio que corresponda \u00e0 propriedade do propriet\u00e1rio no documento do item de mercearia que ele est\u00e1 carregando.<b>\u00a0 <\/b>E, se n\u00e3o corresponderem, o sistema emitir\u00e1 um erro para o novo item de mercearia, pois n\u00e3o ser\u00e1 aceito.  Agora os usu\u00e1rios t\u00eam sua pr\u00f3pria lista de compras e ela \u00e9 privada, e ningu\u00e9m pode escrever para eles.<\/div>\n<div>Seria fant\u00e1stico se os usu\u00e1rios pudessem adicionar amigos para adicionar itens a uma determinada lista.  O que atualizaremos a seguir na configura\u00e7\u00e3o \u00e9 a capacidade de adicionar um novo tipo de \"documento\" com um \"tipo de documento de amigo\", e esse documento ser\u00e1 usado para conceder aos amigos acesso \u00e0 lista de compras de um determinado usu\u00e1rio.<\/div>\n<pre><code class=\"language-javascript\">{\r\n    \u201dlog\" : [\u201c*\u201d],\r\n    \"databases\": {\r\n        \"grocery-sync\": {\r\n            \u201cserver\u201d:\u201dwalrus:\u201d,\r\n            \u201cbucket\":\"grocery-sync\",\r\n            \"users\": {\r\n      \u201calice\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201citems-alice\u201d]  },\r\n     \u201cbob\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201citems-bob\u201d] }\r\n        },\r\n \u201csync\u201d : \u2018\r\n    function(doc, oldDoc) {\r\n      if (doc.type == \u201cfriends\u201d) {          \/\/process new friends document\r\n       requireUser(doc.owner);          \/\/The owner of the friends\r\n                  access(doc.friends, \u201citems-\u201d+doc.owner);    \r\n                  channel(\u201cprivate-\u201d+doc.owner);\r\n                  access(doc.owner, \u201cprivate-\u201d+doc.owner)   \r\n      } else {\r\n          requireUser(doc.owner)\r\n          channel(\u201citems-\u201d+doc.owner);  }\r\n    } \u2018\r\n    }\r\n}\r\n<\/code><\/pre>\n<div style=\"font-family: 'Helvetica Neue'; font-size: 14px;\">\n<div style=\"font-family: 'Helvetica Neue'; font-size: 14px;\">\n<div style=\"text-align: justify;\">Como agora h\u00e1 uma chave de \"tipo\" nos dois documentos que pode ser diferenciada pelos tipos de documento \"itens\" ou \"amigos\", podemos adicionar uma op\u00e7\u00e3o na fun\u00e7\u00e3o de sincroniza\u00e7\u00e3o para permitir que processemos os diferentes documentos de maneiras diferentes na fun\u00e7\u00e3o de sincroniza\u00e7\u00e3o<\/div>\n<\/div>\n<div>Primeiro, verificamos o tipo de documento para ver se ele \u00e9 do tipo \"friends\" e, em seguida, verificamos se a propriedade do propriet\u00e1rio do documento corresponde ao ID do usu\u00e1rio autenticado atual por meio do m\u00e9todo \"requireUser()\" e, se n\u00e3o corresponder, n\u00f3s o rejeitaremos, pois somente o propriet\u00e1rio pode convidar amigos para atualizar sua lista de compras.  Se a propriedade do propriet\u00e1rio corresponder ao usu\u00e1rio autenticado atual, daremos acesso a todos os amigos por meio do canal \"items-doc.owner\".<\/div>\n<div style=\"font-family: 'Helvetica Neue'; font-size: 14px;\">\n<div style=\"text-align: justify;\">Assim, por exemplo, quando Bob coloca seu documento de amigos para convidar Alice, basicamente damos a Alice acesso ao canal items-bob.<\/div>\n<\/div>\n<div>Em seguida, vamos mapear o documento que \u00e9 do tipo \"amigos\" para um canal chamado<b> <\/b>'private-doc.owner' que, nesse caso, ser\u00e1 'private-bob' e observe que, dessa vez, esse \u00e9 um canal criado dinamicamente.  Ele n\u00e3o \u00e9 criado nos canais de administra\u00e7\u00e3o do registro do usu\u00e1rio, e voc\u00ea v\u00ea que esses canais s\u00e3o criados em tempo real quando o usu\u00e1rio envia um convite pela primeira vez.  Isso significa basicamente que ningu\u00e9m mais ver\u00e1 a lista de amigos que foi convidada pelo usu\u00e1rio, pois ela \u00e9 privada apenas para o pr\u00f3prio usu\u00e1rio.  Em seguida, daremos ao \"doc.owner\" ou ao(s) usu\u00e1rio(s) autenticado(s) atual(is) acesso a esse novo canal privado que foi criado para ele.<\/div>\n<div>A cl\u00e1usula \"else\" \u00e9 onde, se esse n\u00e3o for o documento de um amigo,<b> <\/b>ent\u00e3o esse ser\u00e1 um documento de item de sincroniza\u00e7\u00e3o de compras e, novamente, validamos que a propriedade owner corresponde ao ID de usu\u00e1rio autenticado atual.  Como antes,<b> <\/b>adicionamos os itens ao canal 'items-' para a propriedade do propriet\u00e1rio do item e damos a esse usu\u00e1rio acesso din\u00e2mico a esse canal.<\/div>\n<div>Enquanto atualizamos a fun\u00e7\u00e3o Sync com a l\u00f3gica de troca acima, podemos adicionar um teste adicional para rejeitar qualquer tipo de documento desconhecido; portanto, se n\u00e3o for um documento do tipo \"friends\" ou \"item\", rejeitaremos o documento chamando o m\u00e9todo \"throw()\".<\/div>\n<pre><code class=\"language-javascript\">{\r\n    \u201dlog\" : [\u201c*\u201d],\r\n    \"databases\": {\r\n        \"grocery-sync\": {\r\n            \u201cserver\u201d:\u201dwalrus:\u201d,\r\n            \u201cbucket\":\"grocery-sync\",\r\n            \"users\": {\r\n      \u201calice\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201citems-alice\u201d]  },\r\n      \u201cbob\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201citems-bob\u201d] }\r\n        },\r\n \u201csync\u201d : \u2018\r\n    function(doc, oldDoc) {\r\n      if (doc.type == \u201cfriends\u201d) {          \/\/process new friends document\r\n           requireUser(doc.owner);          \/\/The owner of the friends\r\n                  access(doc.friends, \u201citems-\u201d+doc.owner);    \r\n                  channel(\u201cprivate-\u201d+doc.owner);\r\n                  access(doc.owner, \u201cprivate-\u201d+doc.owner);  \r\n      } \r\n             else if (doc.type == \u201citem\u201d) {\r\n          requireUser(doc.owner);\r\n          channel(\u201citems-\u201d+doc.owner);  \r\n             }\r\n             else{\r\n                 throw({forbidden: \u201cInvalid document type\u201d}); \r\n             }\r\n          }\r\n }\u2018\r\n    }\r\n}\r\n<\/code><\/pre>\n<div>\n<div style=\"font-family: 'Helvetica Neue'; font-size: 14px;\">Voc\u00ea pode ver que adicionamos outra cl\u00e1usula \"else\" para capturar todos os outros tipos de documentos e simplesmente lan\u00e7aremos uma mensagem de \"tipo de documento inv\u00e1lido\", que ser\u00e1 enviada de volta ao cliente.  Essa \u00e9 uma maneira de impedir que as pessoas insiram coisas que n\u00e3o queremos em nosso banco de dados.<\/div>\n<div>Portanto, agora que convidamos amigos, queremos realmente dar a eles a capacidade de escrever novos itens na lista do propriet\u00e1rio.  O que temos de fazer \u00e9 alterar o m\u00e9todo anterior \"requireUser()<b> <\/b>para 'requireAccess()' para que n\u00e3o apenas o propriet\u00e1rio possa gravar itens no canal de itens, mas qualquer pessoa que tenha recebido acesso a esse canal espec\u00edfico tamb\u00e9m possa adicionar\/gravar novos itens.  \u00c9 aqui que os amigos s\u00f3 recebem esse acesso ao canal de itens de um usu\u00e1rio por meio de um convite de um documento de um amigo.<\/div>\n<\/div>\n<pre><code class=\"language-javascript\">{\r\n    \u201dlog\" : [\u201c*\u201d],\r\n    \"databases\": {\r\n        \"grocery-sync\": {\r\n            \u201cserver\u201d:\u201dwalrus:\u201d,\r\n            \u201cbucket\":\"grocery-sync\",\r\n            \"users\": {\r\n      \u201calice\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201citems-alice\u201d]  },\r\n     \u201cbob\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201citems-bob\u201d] }\r\n            },\r\n \u201csync\u201d : \u2018\r\n    function(doc, oldDoc) {\r\n      if (doc.type == \u201cfriends\u201d) {          \/\/process new friends document\r\n        requireUser(doc.owner);          \/\/The owner of the friends\r\n                  access(doc.friends, \u201citems-\u201d+doc.owner);    \r\n                  channel(\u201cprivate-\u201d+doc.owner);\r\n                  access(doc.owner, \u201cprivate-\u201d+doc.owner);   \r\n      } else if (doc.type == \u201citem\u201d) {\r\n          requireAccess(\u201citems-\u201d+doc.owner)\r\n          channel(\u201citems-\u201d+doc.owner);  }\r\n         else{  throw({forbidden: \u201cInvalid document type\u201d}); }\r\n    } \u2018\r\n          }\r\n    }\r\n<\/code><\/pre>\n<div>Em vez do m\u00e9todo 'requireUser()', vamos substitu\u00ed-lo pelo m\u00e9todo<b> <\/b>O m\u00e9todo 'requireAccess(\"items-\"+doc.owner)' agora, basicamente, se voc\u00ea quiser escrever um novo item em uma lista, ter\u00e1 de ter acesso ao canal de itens do usu\u00e1rio espec\u00edfico para o qual deseja adicionar o item.   Alguns recursos adicionais do aplicativo s\u00e3o que, se um amigo escrever um novo item em nossa lista, queremos ter certeza de que ele n\u00e3o poder\u00e1 marcar o item.  Portanto, o que queremos \u00e9 que ele adicione apenas novos itens que n\u00e3o estejam marcados e que somente o propriet\u00e1rio da lista de compras possa marc\u00e1-los adequadamente.  Faremos uma verifica\u00e7\u00e3o adicional quando um amigo escrever um documento, para que o documento n\u00e3o tenha sua propriedade definida como true e, assim, testar o valor booleano da propriedade doc.checked.<\/div>\n<pre><code class=\"language-javascript\">{\r\n    \u201dlog\" : [\u201c*\u201d],\r\n    \"databases\": {\r\n        \"grocery-sync\": {\r\n            \u201cserver\u201d:\u201dwalrus:\u201d,\r\n            \u201cbucket\":\"grocery-sync\",\r\n            \"users\": {\r\n      \u201calice\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201citems-alice\u201d]  },\r\n     \u201cbob\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201citems-bob\u201d] }\r\n            },\r\n \u201csync\u201d : \u2018\r\n    function(doc, oldDoc) {\r\n      if (doc.type == \u201cfriends\u201d) {          \/\/process new friends document\r\n        requireUser(doc.owner);          \/\/The owner of the friends\r\n                          access(doc.friends, \u201citems-\u201d+doc.owner);    \r\n                          channel(\u201cprivate-\u201d+doc.owner);\r\n                          access(doc.owner, \u201cprivate-\u201d+doc.owner);   \r\n      } else if (doc.type == \u201citem\u201d) {\r\n          requireAccess(\u201citems-\u201d+doc.owner)\r\n             if (oldDoc == null) {\r\n               if (doc.check == true) { throw( {forbidden: \u201cnew items cannot be checked\u201d}); }\r\n            }\r\n        channel(\u201citems-\u201d+doc.owner);  }\r\n         else { throw( {forbidden: \u201cInvalid document type\u201d}); }\r\n    } \u2018\r\n          }\r\n    }\r\n<\/code><\/pre>\n<div style=\"text-align: justify;\">Primeiro, verificamos se 'oldDoc' \u00e9 nulo, o que significa que se trata de um item rec\u00e9m-criado.  Portanto, validaremos<b> <\/b>a propriedade 'check' no documento para verificar se ela \u00e9 verdadeira e, se for verdadeira, ent\u00e3o<b> <\/b>lan\u00e7aremos um erro em que os \"novos itens n\u00e3o podem ser verificados\" quando forem criados.  S\u00f3 queremos que os propriet\u00e1rios verifiquem ou desmarquem os itens quando eles forem criados e validaremos isso certificando-nos de que h\u00e1 um (doc e oldDoc), o que significa que h\u00e1 uma atualiza\u00e7\u00e3o para o item e, em seguida, veremos se a propriedade 'check' foi alterada entre a vers\u00e3o anterior do item e a nova vers\u00e3o.  Podemos fazer uma verifica\u00e7\u00e3o simples para garantir que o 'oldDoc' n\u00e3o seja NULL e, em seguida, requireUser(owner), mas tamb\u00e9m queremos que os amigos possam corrigir erros de digita\u00e7\u00e3o no texto do item, mesmo que n\u00e3o possam marcar um item, os amigos podem querer alterar o t\u00edtulo ou o r\u00f3tulo do item.  Em seguida, faremos a valida\u00e7\u00e3o em n\u00edvel de campo para verificar se o oldDoc anterior existe ou n\u00e3o.  Portanto, compararemos \"doc.Checked\" com \"oldDoc.checked\" para ver se houve altera\u00e7\u00e3o.  Ent\u00e3o, se tiver sido alterado, faremos um 'requireUser(owner)' no propriet\u00e1rio do documento, pois ele \u00e9 o \u00fanico que pode alterar a caixa de sele\u00e7\u00e3o.<\/div>\n<pre><code class=\"language-javascript\">{\r\n    \u201dlog\" : [\u201c*\u201d],\r\n    \"databases\": {\r\n        \"grocery-sync\": {\r\n            \u201cserver\u201d:\u201dwalrus:\u201d,\r\n            \u201cbucket\":\"grocery-sync\",\r\n            \"users\": {\r\n      \u201calice\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201citems-alice\u201d]  },\r\n     \u201cbob\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201citems-bob\u201d] }\r\n            },\r\n \u201csync\u201d : \u2018\r\n    function(doc, oldDoc) {\r\n      if (doc.type == \u201cfriends\u201d) {          \/\/process new friends document\r\n        requireUser(doc.owner);          \/\/The owner of the friends\r\n                          access(doc.friends, \u201citems-\u201d+doc.owner);    \r\n                          channel(\u201cprivate-\u201d+doc.owner);\r\n                          access(doc.owner, \u201cprivate-\u201d+doc.owner);   \r\n      } else if (doc.type == \u201citem\u201d) {\r\n          requireAccess(\u201citems-\u201d+doc.owner)\r\n             if (oldDoc == null) {\r\n               if (doc.check == true) { throw( {forbidden: \u201cnew items cannot be checked\u201d}); }\r\n              else {\r\n                if (doc.check != oldDoc.check) {  requireUser(doc.owner); } \r\n              }\r\n            }\r\n        channel(\u201citems-\u201d+doc.owner);  }\r\n         else { throw( {forbidden: \u201cInvalid document type\u201d}); }\r\n    } \u2018\r\n          }\r\n    }\r\n<\/code><\/pre>\n<div>Observando a \"cl\u00e1usula else<b> <\/b>h\u00e1 um c\u00f3digo adicional para verificar se o valor \"check\" foi alterado entre a vers\u00e3o anterior do item e a nova vers\u00e3o que est\u00e1 sendo enviada.  Se tiver sido alterado, exigiremos que o usu\u00e1rio autenticado atual seja o propriet\u00e1rio do documento.<\/div>\n<div>Assim, somente o propriet\u00e1rio pode alterar a caixa de sele\u00e7\u00e3o.  Mas outros amigos do propriet\u00e1rio podem alterar coisas como o t\u00edtulo do item.<\/div>\n<div>Temos um \u00faltimo problema que queremos analisar e resolver.  Queremos ter certeza de que ningu\u00e9m poder\u00e1 alterar o \"propriet\u00e1rio\" de um item depois que ele for criado.  Isso significa que os amigos podem fazer modifica\u00e7\u00f5es nos r\u00f3tulos, mas n\u00e3o podem alterar a caixa de sele\u00e7\u00e3o em um item ou alterar o propriet\u00e1rio real de um item.  Vamos ver como podemos resolver esse problema na configura\u00e7\u00e3o final.<\/div>\n<pre><code class=\"language-javascript\">{\r\n    \u201dlog\" : [\u201c*\u201d],\r\n    \"databases\": {\r\n        \"grocery-sync\": {\r\n            \u201cserver\u201d:\u201dwalrus:\u201d,\r\n            \u201cbucket\":\"grocery-sync\",\r\n            \"users\": {\r\n      \u201calice\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201citems-alice\u201d]  },\r\n     \u201cbob\u201d: {\r\n  \u201cdisabled\u201d : false,\r\n  \u201cpassword\u201d: \u201cpassword\u201d,\r\n  \u201cadmin_channels\u201d:[\u201citems-bob\u201d] }\r\n            },\r\n \u201csync\u201d : \u2018\r\n    function(doc, oldDoc) {\r\n      if (doc.type == \u201cfriends\u201d) {          \/\/process new friends document\r\n        requireUser(doc.owner);          \/\/The owner of the friends\r\n                          access(doc.friends, \u201citems-\u201d+doc.owner);    \r\n                          channel(\u201cprivate-\u201d+doc.owner);\r\n                          access(doc.owner, \u201cprivate-\u201d+doc.owner);   \r\n      } else if (doc.type == \u201citem\u201d) {\r\n          requireAccess(\u201citems-\u201d+doc.owner)\r\n             if (oldDoc == null) {\r\n               if (doc.check == true) { throw( {forbidden: \u201cnew items cannot be checked\u201d}); }\r\n              else {\r\n                if (doc.owner != oldDoc.owner) {  throw({forbidden: \u201cQuits Stealing Items\u201d}); } \r\n                if (doc.check != oldDoc.check) {  requireUser(doc.owner); } \r\n              }\r\n            }\r\n        channel(\u201citems-\u201d+doc.owner);  }\r\n         else { throw( {forbidden: \u201cInvalid document type\u201d}); }\r\n    } \u2018\r\n          }\r\n    }\r\n<\/code><\/pre>\n<div style=\"text-align: justify;\">Portanto, faremos uma verifica\u00e7\u00e3o adicional e, se essa for uma atualiza\u00e7\u00e3o em que 'oldDoc != nil' e o propriet\u00e1rio da nova vers\u00e3o do documento n\u00e3o corresponder ao propriet\u00e1rio da vers\u00e3o anterior (doc.owner != oldDoc.owner), lan\u00e7aremos um erro.  Agora, voc\u00ea pode ver que estamos fazendo um teste adicional para que, se o propriet\u00e1rio tiver mudado entre a vers\u00e3o anterior e a vers\u00e3o atual, lan\u00e7aremos um erro basicamente de volta ao cliente, pois ele n\u00e3o pode alterar o propriet\u00e1rio do documento.<\/div>\n<div style=\"text-align: justify;\"><\/div>\n<p style=\"text-align: justify;\"><strong>[3] Transporte de dados no fio<\/strong><\/p>\n<p style=\"text-align: justify;\">Agora, al\u00e9m das quest\u00f5es de autentica\u00e7\u00e3o e leitura\/grava\u00e7\u00e3o de dados para acesso do usu\u00e1rio com rela\u00e7\u00e3o \u00e0 seguran\u00e7a, o pr\u00f3ximo t\u00f3pico \u00e9 garantir que os dados estejam protegidos ao serem transmitidos para um ponto de extremidade remoto.  O Sync Gateway \u00e9 compat\u00edvel com SSL e TLS no transporte.  \u00c9 f\u00e1cil configurar no arquivo de configura\u00e7\u00e3o do Sync Gateway para ativar o SSL no Sync Gateway para que seu aplicativo m\u00f3vel tenha mais seguran\u00e7a de dados.<\/p>\n<p style=\"text-align: justify;\"><strong>[4] Armazenamento de dados<\/strong><\/p>\n<p style=\"text-align: justify;\">Para armazenamento de dados no cliente<b>, <\/b>voc\u00ea est\u00e1 realmente fazendo a criptografia do sistema de arquivos no dispositivo.  H\u00e1 boas informa\u00e7\u00f5es sobre o que voc\u00ea precisa fazer para criptografar o banco de dados local do Couchbase Lite no portal do desenvolvedor m\u00f3vel.  Estamos falando de um ambiente de nuvem seguro e de sua configura\u00e7\u00e3o para a criptografia do sistema de arquivos no cliente.<\/p>\n<p style=\"text-align: center;\"><a href=\"https:\/\/bit.ly\/CBNYC2015\"><img decoding=\"async\" src=\"\/wp-content\/original-assets\/2015\/october\/couchbase-live-new-york-couchbase-mobile-102---how-to-add-secure-sync-to-your-mobile-applications\/events.cbliveny.blog.banner.jpg\" \/><\/a><\/p>\n<p style=\"text-align: justify;\"><strong>Resumo<\/strong><\/p>\n<p style=\"text-align: justify;\">O Sync Gateway \u00e9 realmente a pe\u00e7a<b> <\/b>que une o Couchbase Lite, a estrutura que est\u00e1 no dispositivo incorporado. Voc\u00ea tem o Couchbase Server em execu\u00e7\u00e3o na nuvem, e o Sync Gateway une tudo isso.  O Sync Gateway tem um punhado de fun\u00e7\u00f5es-chave que ele fornece para transformar um aplicativo em execu\u00e7\u00e3o no dispositivo local, que \u00e9 um aplicativo aut\u00f4nomo desconectado, em uma experi\u00eancia de sincroniza\u00e7\u00e3o com v\u00e1rios usu\u00e1rios e com todos os recursos.  O que \u00e9 mostrado acima \u00e9 como podemos serializar as coisas no banco de dados por meio da itera\u00e7\u00e3o no arquivo de configura\u00e7\u00e3o Sync Function.<\/p>\n<p style=\"text-align: justify;\">Em seguida, veremos a classe de componente de ouvinte HTTP do Couchbase Lite e a sess\u00e3o do Couchbase Mobile 103 sobre como ativar o recurso Peer-to-Peer, em que voc\u00ea pode criar experi\u00eancias sociais exclusivas no aplicativo com \"Building a Peer-to-Peer App with Couchbase Mobile\".<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>From the 102 session in the Couchbase LIVE New York mobile track, we continued iterating on the Couchbase Mobile sample application that was described in code from the &#8220;Couchbase Mobile 101: How to Build Your First Mobile App&#8221; session. In [&hellip;]<\/p>","protected":false},"author":30,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1815,2366],"tags":[],"ppma_author":[8983],"class_list":["post-1985","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-best-practices-and-tutorials","category-sync-gateway"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.9 (Yoast SEO v25.9) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>How to Add Secure Sync to your Mobile Applications<\/title>\n<meta name=\"description\" content=\"How to Add Secure Sync to your Mobile Applications&quot; by securing the Grocery Sync sample application which can be found on the Github repo for iOS &amp; Android.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/pt\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Couchbase LIVE New York: Couchbase Mobile 102 - How to Add Secure Sync to your Mobile Applications\" \/>\n<meta property=\"og:description\" content=\"How to Add Secure Sync to your Mobile Applications&quot; by securing the Grocery Sync sample application which can be found on the Github repo for iOS &amp; Android.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/pt\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2015-10-23T08:04:40+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T02:58:53+00:00\" \/>\n<meta name=\"author\" content=\"William Hoang, Mobile Developer Advocate, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"William Hoang, Mobile Developer Advocate, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"21 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/\"},\"author\":{\"name\":\"William Hoang, Mobile Developer Advocate, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/425717456c198fdf9aaa5d7a6d42ad32\"},\"headline\":\"Couchbase LIVE New York: Couchbase Mobile 102 &#8211; How to Add Secure Sync to your Mobile Applications\",\"datePublished\":\"2015-10-23T08:04:40+00:00\",\"dateModified\":\"2025-06-14T02:58:53+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/\"},\"wordCount\":3449,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"articleSection\":[\"Best Practices and Tutorials\",\"Sync Gateway\"],\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/\",\"name\":\"How to Add Secure Sync to your Mobile Applications\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2015-10-23T08:04:40+00:00\",\"dateModified\":\"2025-06-14T02:58:53+00:00\",\"description\":\"How to Add Secure Sync to your Mobile Applications\\\" by securing the Grocery Sync sample application which can be found on the Github repo for iOS & Android.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/#breadcrumb\"},\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"width\":1800,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Couchbase LIVE New York: Couchbase Mobile 102 &#8211; How to Add Secure Sync to your Mobile Applications\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"pt-BR\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/425717456c198fdf9aaa5d7a6d42ad32\",\"name\":\"William Hoang, Mobile Developer Advocate, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/650445f1ea30314c4f3555dd680154f5\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/b912c9a97568a859697ee195432d0bd7cc3ed67d720ae2e6588b67313fa49e08?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/b912c9a97568a859697ee195432d0bd7cc3ed67d720ae2e6588b67313fa49e08?s=96&d=mm&r=g\",\"caption\":\"William Hoang, Mobile Developer Advocate, Couchbase\"},\"description\":\"William was a Developer Advocate on the Mobile Engineering\/Developer Experience team at Couchbase. His love for coffee and code has transcended him into the world of mobile while appreciating the offline in-person experiences. Prior, William worked on the Developer Relations team over at Twitter, BlackBerry, and Microsoft while also having been a Software Embedded GPS engineer at Research In Motion. William graduated from McGill University in Electrical Software Engineering\",\"url\":\"https:\/\/www.couchbase.com\/blog\/pt\/author\/william-hoang\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"How to Add Secure Sync to your Mobile Applications","description":"How to Add Secure Sync to your Mobile Applications\" by securing the Grocery Sync sample application which can be found on the Github repo for iOS & Android.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/pt\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/","og_locale":"pt_BR","og_type":"article","og_title":"Couchbase LIVE New York: Couchbase Mobile 102 - How to Add Secure Sync to your Mobile Applications","og_description":"How to Add Secure Sync to your Mobile Applications\" by securing the Grocery Sync sample application which can be found on the Github repo for iOS & Android.","og_url":"https:\/\/www.couchbase.com\/blog\/pt\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/","og_site_name":"The Couchbase Blog","article_published_time":"2015-10-23T08:04:40+00:00","article_modified_time":"2025-06-14T02:58:53+00:00","author":"William Hoang, Mobile Developer Advocate, Couchbase","twitter_card":"summary_large_image","twitter_misc":{"Written by":"William Hoang, Mobile Developer Advocate, Couchbase","Est. reading time":"21 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/"},"author":{"name":"William Hoang, Mobile Developer Advocate, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/425717456c198fdf9aaa5d7a6d42ad32"},"headline":"Couchbase LIVE New York: Couchbase Mobile 102 &#8211; How to Add Secure Sync to your Mobile Applications","datePublished":"2015-10-23T08:04:40+00:00","dateModified":"2025-06-14T02:58:53+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/"},"wordCount":3449,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","articleSection":["Best Practices and Tutorials","Sync Gateway"],"inLanguage":"pt-BR","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/","url":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/","name":"How to Add Secure Sync to your Mobile Applications","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2015-10-23T08:04:40+00:00","dateModified":"2025-06-14T02:58:53+00:00","description":"How to Add Secure Sync to your Mobile Applications\" by securing the Grocery Sync sample application which can be found on the Github repo for iOS & Android.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/#breadcrumb"},"inLanguage":"pt-BR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/"]}]},{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","width":1800,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-mobile-102-how-to-add-secure-sync-to-your-mobile-applications\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Couchbase LIVE New York: Couchbase Mobile 102 &#8211; How to Add Secure Sync to your Mobile Applications"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"Blog do Couchbase","description":"Couchbase, o banco de dados NoSQL","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"pt-BR"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"Blog do Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/425717456c198fdf9aaa5d7a6d42ad32","name":"William Hoang, defensor do desenvolvedor m\u00f3vel, Couchbase","image":{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/650445f1ea30314c4f3555dd680154f5","url":"https:\/\/secure.gravatar.com\/avatar\/b912c9a97568a859697ee195432d0bd7cc3ed67d720ae2e6588b67313fa49e08?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/b912c9a97568a859697ee195432d0bd7cc3ed67d720ae2e6588b67313fa49e08?s=96&d=mm&r=g","caption":"William Hoang, Mobile Developer Advocate, Couchbase"},"description":"William foi um defensor do desenvolvedor na equipe de engenharia m\u00f3vel\/experi\u00eancia do desenvolvedor na Couchbase. Seu amor por caf\u00e9 e c\u00f3digo o levou ao mundo dos dispositivos m\u00f3veis, ao mesmo tempo em que apreciava as experi\u00eancias presenciais off-line. Antes disso, William trabalhou na equipe de rela\u00e7\u00f5es com desenvolvedores do Twitter, BlackBerry e Microsoft, al\u00e9m de ter sido engenheiro de GPS incorporado a software na Research In Motion. William se formou na McGill University em Engenharia El\u00e9trica de Software","url":"https:\/\/www.couchbase.com\/blog\/pt\/author\/william-hoang\/"}]}},"authors":[{"term_id":8983,"user_id":30,"is_guest":0,"slug":"william-hoang","display_name":"William Hoang, Mobile Developer Advocate, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/b912c9a97568a859697ee195432d0bd7cc3ed67d720ae2e6588b67313fa49e08?s=96&d=mm&r=g","author_category":"","last_name":"Hoang","first_name":"William","job_title":"","user_url":"","description":"William foi um defensor do desenvolvedor na equipe de engenharia m\u00f3vel\/experi\u00eancia do desenvolvedor na Couchbase. Seu amor por caf\u00e9 e c\u00f3digo o levou ao mundo dos dispositivos m\u00f3veis, ao mesmo tempo em que apreciava as experi\u00eancias presenciais off-line. Antes disso, William trabalhou na equipe de rela\u00e7\u00f5es com desenvolvedores do Twitter, BlackBerry e Microsoft, al\u00e9m de ter sido engenheiro de GPS incorporado a software na Research In Motion. William se formou na McGill University em Engenharia El\u00e9trica de Software"}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/1985","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/users\/30"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/comments?post=1985"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/1985\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media?parent=1985"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/categories?post=1985"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/tags?post=1985"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/ppma_author?post=1985"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}