Com a chegada de estruturas de front-end ricas em recursos, como AngularJS, mais e mais lógica está sendo implementada no front-end, como manipulação / validação de dados, autenticação e muito mais. Satellizer, um módulo de autenticação baseado em token fácil de usar para AngularJS, simplifica o processo de implementação de mecanismo de autenticação em AngularJS. A biblioteca vem com suporte integrado para Google, Facebook, LinkedIn, Twitter, Instagram, GitHub, Bitbucket, Yahoo, Twitch e contas da Microsoft (Windows Live).
Neste artigo, construiremos um webapp muito simples, semelhante ao Aqui que permite que você faça o login e veja as informações do usuário atual.
Estas são duas palavras assustadoras que você costuma encontrar quando seu aplicativo começa a integrar um sistema de usuário. De acordo com a Wikipedia:
Autenticação é o ato de confirmar a verdade de um atributo de um único dado (um dado) afirmado como verdadeiro por uma entidade.
Autorização é a função de especificar direitos de acesso a recursos relacionados à segurança da informação e segurança de computadores em geral e ao controle de acesso em particular.
Em termos leigos, vamos dar um exemplo de um site de blog com algumas pessoas trabalhando nele. Os blogueiros escrevem artigos e o gerente valida o conteúdo. Cada pessoa pode se autenticar (fazer login) no sistema, mas seus direitos (autorização) são diferentes, portanto, o blogueiro não pode validar o conteúdo, enquanto o gerente pode.
Você pode criar seu próprio sistema de autenticação no AngularJS seguindo alguns tutoriais como este muito detalhado: Tutorial JSON Web Token: Um Exemplo no Laravel e AngularJS . Sugiro ler este artigo, pois ele explica muito bem o JWT (JSON Web Token) e mostra uma maneira simples de implementar a autenticação em AngularJS usando diretamente o armazenamento local e interceptores HTTP.
Então, por que Satellizer? A principal razão é que ele suporta um punhado de logins de redes sociais, como Facebook, Twitter, etc. Hoje em dia, especialmente para sites usados no celular, digitar o nome de usuário e a senha é bastante complicado e os usuários esperam poder usar seu site com poucos obstáculos usando logins sociais. Como integrar o SDK de cada rede social e seguir suas documentações é bastante repetitivo, seria bom oferecer suporte a esses logins sociais com o mínimo de esforço.
Além disso, o Satellizer é um ativo projeto no Github. Ativo é a chave aqui, pois esses SDKs mudam com bastante frequência e você não quer ler sua documentação de vez em quando (qualquer pessoa que trabalhe com o SDK do Facebook sabe como isso é irritante)
É aqui que as coisas começam a ficar interessantes.
Vamos construir um aplicativo da web que tem um mecanismo de login / registro regular (ou seja, usando nome de usuário, senha) e também oferece suporte para logins sociais. Este webapp é muito simples, pois tem apenas 3 páginas:
Para backend, usaremos Python e Flask. Python e o framework Flask são bastante expressivos, então espero que portar o código para outras linguagens / frameworks não seja muito difícil. Vamos, é claro, usar AngularJS para front-end. E para os logins sociais, iremos integrar com o Facebook apenas por ser a rede social mais popular no momento.
Vamos começar!
Aqui está como iremos estruturar nosso código:
- app.py - static/ - index.html - app.js - bower.json - partials/ - login.tpl.html - home.tpl.html - secret.tpl.html
Todo o código de back-end está em app.py . O código do front-end é colocado em estática / pasta. Por padrão, o Flask servirá automaticamente o conteúdo de estática / pasta. Todas as visualizações parciais estão em static / partials / e gerenciadas pelo módulo ui.router.
Para começar a codificar o back-end, precisaremos do Python 2.7. * E instalar as bibliotecas necessárias usando pip. Você pode, é claro, usar virtualenv para isolar um ambiente Python. Abaixo está a lista de módulos Python necessários para colocar em requirements.txt:
Flask==0.10.1 PyJWT==1.4.0 Flask-SQLAlchemy==1.0 requests==2.7.0
Para instalar todas essas dependências:
pip install -r requirements.txt
Dentro app.py temos algum código inicial para inicializar o Flask (as instruções de importação são omitidas por questões de brevidade):
app = Flask(__name__) @app.route('/') def index(): return flask.redirect('/static/index.html') if __name__ == '__main__': app.run(debug=True)
Em seguida nós iniciar bower e instalar AngularJS e ui.router:
bower init # here you will need to answer some question. when in doubt, just hit enter :) bower install angular angular-ui-router --save # install and save these dependencies into bower.json
Assim que essas bibliotecas forem instaladas, precisamos incluir AngularJS e ui-router em index.html e crie roteamentos para 3 páginas: home, login e secret.
Home Login Secret
Abaixo está o código que precisamos em main.js para configurar o roteamento:
var app = angular.module('DemoApp', ['ui.router']); app.config(function ($stateProvider, $urlRouterProvider) { $stateProvider .state('home', { url: '/home', templateUrl: 'partials/home.tpl.html' }) .state('secret', { url: '/secret', templateUrl: 'partials/secret.tpl.html', }) .state('login', { url: '/login', templateUrl: 'partials/login.tpl.html' }); $urlRouterProvider.otherwise('/home'); });
Neste ponto, se você executar o servidor python app.py , você deve ter esta interface básica em http: // localhost: 5000
Os links Home, Login e Secret devem funcionar neste ponto e mostrar o conteúdo dos modelos correspondentes.
Parabéns, você acabou de configurar o esqueleto! Se você encontrar algum erro, verifique o código no GitHub
Ao final desta etapa, você terá um webapp que pode registrar / fazer login usando e-mail e senha.
A primeira etapa é configurar o back-end. Precisamos de um modelo de usuário e uma maneira de gerar o token JWT para um determinado usuário. O modelo de usuário mostrado abaixo é realmente simplificado e não executa nem mesmo nenhuma verificação básica, como o campo if o email contém “@”, ou se o campo senha contém pelo menos 6 caracteres, etc.
class User(db.Model): id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(100), nullable=False) password = db.Column(db.String(100)) def token(self): payload = { 'sub': self.id, 'iat': datetime.utcnow(), 'exp': datetime.utcnow() + timedelta(days=14) } token = jwt.encode(payload, app.config['TOKEN_SECRET']) return token.decode('unicode_escape')
Usamos o módulo jwt em python para gerar a parte da carga útil em JWT. As partes iat e exp correspondem ao carimbo de data / hora em que o token foi criado e expirou. Neste código, o token expirará em 2 semanas.
Depois que o usuário modelo foi criado, podemos adicionar os endpoints de “login” e “registro”. O código para ambos é bastante semelhante, então aqui vou mostrar apenas a parte do “registro”. Observe que, por padrão, o Satellizer chamará os terminais / auth / login e / auth / signup para o “login” e “registro” respectivamente.
@app.route('/auth/signup', methods=['POST']) def signup(): data = request.json email = data['email'] password = data['password'] user = User(email=email, password=password) db.session.add(user) db.session.commit() return jsonify(token=user.token())
Vamos verificar o endpoint usando curl primeiro:
curl localhost:5000/auth/signup -H 'Content-Type: application/json' -X POST -d '{'email':' [email protected] ','password':'xyz'}'
O resultado deve ser assim:
{ 'token': 'very long string….' }
Agora que o back-end está pronto, vamos atacar o front-end! Primeiro, precisamos instalar o satellizer e adicioná-lo como uma dependência em main.js:
bower install satellizer --save
Adicione o satellizer como dependência:
var app = angular.module('DemoApp', ['ui.router', 'satellizer']);
O login e a inscrição no satellizer são bastante simples em comparação com toda a configuração até agora:
$scope.signUp = function () { $auth .signup({email: $scope.email, password: $scope.password}) .then(function (response) { // set the token received from server $auth.setToken(response); // go to secret page $state.go('secret'); }) .catch(function (response) { console.log('error response', response); }) };
Se você tiver alguma dificuldade para configurar o código, pode dar uma olhada no código no GitHub .
Sim, está correto! Até agora, qualquer pessoa pode acessar a página secreta sem fazer login.
É hora de adicionar algum interceptor no AngularJS para ter certeza de que se alguém for para a página secreta e se esse usuário não estiver conectado, ele será redirecionado para a página de login.
Primeiro, devemos adicionar um sinalizador requiredLogin para distinguir a página secreta de outras.
.state('secret', { url: '/secret', templateUrl: 'partials/secret.tpl.html', controller: 'SecretCtrl', data: {requiredLogin: true} })
A parte “data” será usada no evento $ stateChangeStart que é disparado cada vez que o roteamento muda:
app.run(function ($rootScope, $state, $auth) { $rootScope.$on('$stateChangeStart', function (event, toState) { var requiredLogin = false; // check if this state need login if (toState.data && toState.data.requiredLogin) requiredLogin = true; // if yes and if this user is not logged in, redirect him to login page if (requiredLogin && !$auth.isAuthenticated()) { event.preventDefault(); $state.go('login'); } }); });
Agora, o usuário não pode ir diretamente para a página secreta sem fazer login. Viva!
Como de costume, o código desta etapa pode ser encontrado Aqui .
Neste momento, não há nada realmente secreto na página secreta. Vamos colocar algo pessoal aí.
Esta etapa começa criando um ponto de extremidade no back-end que só pode ser acessado por um usuário autenticado, como um token válido. O ponto final /do utilizador abaixo retorna o ID do usuário e o email do usuário correspondente ao token.
@app.route('/user') def user_info(): # the token is put in the Authorization header if not request.headers.get('Authorization'): return jsonify(error='Authorization header missing'), 401 # this header looks like this: “Authorization: Bearer {token}” token = request.headers.get('Authorization').split()[1] try: payload = jwt.decode(token, app.config['TOKEN_SECRET']) except DecodeError: return jsonify(error='Invalid token'), 401 except ExpiredSignature: return jsonify(error='Expired token'), 401 else: user_id = payload['sub'] user = User.query.filter_by(id=user_id).first() if user is None: return jsonify(error='Should not happen ...'), 500 return jsonify(id=user.id, email=user.email), 200 return jsonify(error='never reach here...'), 500
Novamente, fazemos uso do módulo jwt para decodificar o token JWT incluído no cabeçalho de 'Autorização' e para lidar com o caso em que o token expirou ou não é válido.
Vamos testar este endpoint usando curl. Primeiro, precisamos obter um token válido:
curl localhost:5000/auth/signup -H 'Content-Type: application/json' -X POST -d '{'email':' [email protected] ','password':'xyz'}'
Então, com este token:
curl localhost:5000/user -H 'Authorization: Bearer {put the token here}'
O que dá este resultado:
{ 'email': ' [email protected] ', 'id': 1 }
Agora precisamos incluir este endpoint no Controlador secreto. Isso é muito simples, pois precisamos apenas chamar o endpoint usando o módulo $ http normal. O token é inserido automaticamente no cabeçalho pelo Satellizer, então não precisamos nos preocupar com todos os detalhes de salvar o token e depois colocá-lo no cabeçalho correto.
getUserInfo(); function getUserInfo() { $http.get('/user') .then(function (response) { $scope.user = response.data; }) .catch(function (response) { console.log('getUserInfo error', response); }) }
Por fim, temos algo verdadeiramente pessoal na página secreta!
O código desta etapa está ativado GitHub .
Uma coisa boa sobre o Satellizer, como mencionado no início, é que torna a integração do login social muito mais fácil. No final desta etapa, os usuários podem fazer o login usando sua conta do Facebook!
A primeira coisa a fazer é criar um aplicativo na página de desenvolvedores do Facebook para ter um ID do aplicativo e um código secreto. Por favor segue developers.facebook.com/docs/apps/register para criar uma conta de desenvolvedor do Facebook se você ainda não tiver uma e crie um aplicativo de site. Depois disso, você terá o ID do aplicativo e o segredo do aplicativo como na captura de tela abaixo.
Assim que o usuário decidir se conectar ao Facebook, o Satellizer enviará um código de autorização ao endpoint / auth / facebook . Com este código de autorização, o back-end pode recuperar um token de acesso do Facebook / oauth endpoint que permite a chamada para a API Graph do Facebook para obter informações do usuário, como localização, user_friends, e-mail do usuário, etc.
Também precisamos saber se uma conta de usuário é criada com o Facebook ou por meio de inscrição regular. Para fazer isso, adicionamos ID do Facebook ao nosso modelo de usuário.
facebook_id = db.Column(db.String(100))
O segredo do Facebook é configurado por meio das variáveis env FACEBOOK_SECRET que adicionamos app.config .
app.config['FACEBOOK_SECRET'] = os.environ.get('FACEBOOK_SECRET')
Então, para lançar o app.py , você deve definir esta variável env:
FACEBOOK_SECRET={your secret} python app.py
Aqui está o método que lida com os logins do Facebook. Por padrão, o Satellizer irá chamar o endpoint / auth / facebook .
@app.route('/auth/facebook', methods=['POST']) def auth_facebook(): access_token_url = 'https://graph.facebook.com/v2.3/oauth/access_token' graph_api_url = 'https://graph.facebook.com/v2.5/me?fields=id,email' params = { 'client_id': request.json['clientId'], 'redirect_uri': request.json['redirectUri'], 'client_secret': app.config['FACEBOOK_SECRET'], 'code': request.json['code'] } # Exchange authorization code for access token. r = requests.get(access_token_url, params=params) # use json.loads instead of urlparse.parse_qsl access_token = json.loads(r.text) # Step 2. Retrieve information about the current user. r = requests.get(graph_api_url, params=access_token) profile = json.loads(r.text) # Step 3. Create a new account or return an existing one. user = User.query.filter_by(facebook_id=profile['id']).first() if user: return jsonify(token=user.token()) u = User(facebook_id=profile['id'], email=profile['email']) db.session.add(u) db.session.commit() return jsonify(token=u.token())
Para enviar uma solicitação ao servidor do Facebook, usamos as úteis solicitações do módulo. Agora, a parte difícil do back-end está concluída. No front-end, adicionar o login do Facebook é bastante simples. Primeiro, precisamos informar ao Satellizer nosso ID do Facebook adicionando este código em app.config função:
$authProvider.facebook({ clientId: {your facebook app id}, // by default, the redirect URI is http://localhost:5000 redirectUri: 'http://localhost:5000/static/index.html' });
Para fazer o login usando o Facebook, podemos simplesmente ligar:
$auth.authenticate(“facebook”)
Como de costume, você pode verificar o código no GitHub
Neste momento, o webapp está completo em termos de funcionalidade. O usuário pode fazer o login / registrar-se usando e-mail e senha normais ou usando o Facebook. Uma vez logado, o usuário pode ver sua página secreta.
A interface não é muito bonita neste ponto, então vamos adicionar um pouco de Bootstrap para o layout e o módulo torradeira angular para lidar bem com uma mensagem de erro, como quando o login falha.
O código para esta parte embelezadora pode ser encontrado Aqui .
Este artigo mostra uma integração passo a passo do Satellizer em um (simples) webapp AngularJS. Com o Satellizer, podemos adicionar facilmente outros logins sociais, como Twitter, Linkedin e muito mais. O código no front-end é exatamente o mesmo do artigo. No entanto, o back-end varia, pois os SDKs de redes sociais têm terminais diferentes com protocolos diferentes. Você pode dar uma olhada em https://github.com/sahat/satellizer/blob/master/examples/server/python/app.py que contém exemplos para Facebook, Github, Google, Linkedin, Twiter e Bitbucket. Em caso de dúvida, você deve dar uma olhada na documentação sobre https://github.com/sahat/satellizer .
Relacionado: Login com um clique com Blockchain: um tutorial da MetaMask