Autenticação e controle de acesso

** Atenção: a API descrito neste capítulo é novo e sujeitas a alterações. Certifique-se de manter seu código atualizado **

py4web vem com um um objecto Auth e um sistema de encaixes para a autenticação do utilizador e de controlo de acesso. Ele tem o mesmo nome que o web2py correspondente e tem a mesma finalidade, mas a API e design interno é muito diferente.

Para usá-lo, em primeiro lugar você precisa importá-lo, instanciá-lo, configurá-lo, e habilitá-lo.

from py4web.utils.auth import Auth
auth = Auth(session, db)
# (configure here)
auth.enable()

A etapa de importação é óbvia. A segunda etapa não executar qualquer operação que não dizendo o objeto Auth qual objeto sessão para usar e qual banco de dados para uso. Auth dados são armazenados em `` sessão [ “user”] `` e, se um usuário estiver logado, o ID do usuário é armazenado na sessão [ ‘user’] [ ‘id’]. O objecto dB é utilizado para armazenar informação sobre o utilizador persistente numa tabela `` auth_user`` com os seguintes campos:

  • nome do usuário

  • o email

  • senha

  • primeiro nome

  • último nome

  • sso_id (usado para single sign on, ver mais adiante)

  • action_token (usado para verificar e-mail, bloquear usuários e outras tarefas, também ver mais adiante).

Se o `` auth_user`` tabela não existir ele será criado.

A etapa de configuração é opcional e discutida mais tarde.

A `` auth.enable () `` passo cria e expõe os seguintes APIs RESTful:

  • {Nomeaplic} / auth / api / registo (POST)

  • {Nomeaplic} / auth / api / Login (POST)

  • {Nomeaplic} / auth / api / request_reset_password (POST)

  • {Nomeaplic} / auth / api / reset_password (POST)

  • {Appname} / auth / api / verify_email (GET, POST)

  • {Nomeaplic} / auth / api / Sair (GET, POST) (+)

  • {Nomeaplic} / auth / api / perfil (GET, POST) (+)

  • {Nomeaplic} / auth / api / change_password (POST) (+)

  • {Nomeaplic} / auth / api / change_email (POST) (+)

Os que estão marcados com um (+) requerem um usuário conectado.

Interface de autenticação

Você pode criar sua própria interface do usuário da web para usuários de login usando as APIs acima, mas py4web fornece um como exemplo, implementada nos seguintes arquivos:

  • _Scaffold / templates / auth.html

  • _scaffold / static / componentes / auth.js

  • _Scaffold / static / componentes / auth.html

Os arquivos do componente (js / html) definem um componente Vue `` <auth /> `` que é usado na auth.html arquivo de modelo da seguinte forma:

[[extend "layout.html"]]
<div id="vue">
  <div class="columns">
    <div class="column is-half is-offset-one-quarter" style="border : 1px solid #e1e1e1; border-radius: 10px">
      <auth plugins="local,oauth2google,oauth2facebook"></auth>
    </div>
  </div>
</div>
[[block page_scripts]]
<script src="js/utils.js"></script>
<script src="components/auth.js"></script>
<script>utils.app().start();</script>
[[end]]

Você pode muito bem usar esse arquivo modificado-un. Estende-se o layout atual e incorpora o `` <auth /> `` componente na página. Em seguida, usa `` utils.app () start ();. `` (Magia py4web) para processar o conteúdo de `` <div id = «vue»> … </ div> `` usando Vue.js. `` componentes / auth.js`` também carrega automaticamente `` componentes / auth.html`` para o espaço reservado componente (mais mágicas py4web). O componente é responsável para render o login / registo / etc formas usando reactivo html e Geting / dados de lançamento com a API de serviço de autenticação.

Se você precisa mudar o estilo do componente que você pode editar “componentes / auth.html” para atender às suas necessidades. É principalmente HTML com algum especial Vue `` v- * `` tags.

Usando o Auth

Há duas maneiras de usar o objeto Auth em uma ação:

@action('index')
@action.uses(auth)
def index():
    user = auth.get_user()
    return 'hello {first_name}'.format(**user) if user else 'not logged in'

Com `` @ action.uses (auth) `` nós dizemos py4web que esta ação precisa ter informações sobre o usuário, em seguida, tentar analisar a sessão para uma sessão de usuário.

@action('index')
@action.uses(auth.user)
def index():
    user = auth.get_user()
    return 'hello {first_name}'.format(**user)'

Aqui `` @ action.uses (auth.user) `` diz py4web que essa ação requer um usuário conectado e deve redirecionar para login se nenhum usuário está logado.

Plugins de Autenticação

Plugins are defined in “py4web/utils/auth_plugins” and they have a hierarchical structure. Some are exclusive and some are not. For example, default, LDAP, PAM, and SAML are exclusive (the developer has to pick one). Default, Google, Facebook, and Twitter OAuth are not exclusive (the developer can pick them all and the user gets to choose using the UI).

O `` <auth /> `` componentes irá se adaptar automaticamente para formulários de login de exibição, conforme exigido pelos plugins instalados.

** Neste momento, não podemos garantir que os seguintes plugins funcionam bem. Eles foram portados de web2py onde eles não funcionam, mas o teste ainda é necessária **

PAM

Configurando PAM é o mais fácil:

from py4web.utils.auth_plugins.pam_plugin import PamPlugin
auth.register_plugin(PamPlugin())

Este, como todos os plugins deve ser importado e registrado. Uma vez registrado o UI (componentes / auth) e as APIs RESTful sabe como lidar com isso. O construtor desta plugins não requer quaisquer argumentos (onde outros plugins fazer).

O `` auth.register_plugin (…) `` must ** ** vir antes do `` auth.enable () ``, uma vez que não faz sentido para expor APIs antes de plugins desejados são montados.

LDAP

from py4web.utils.auth_plugins.ldap_plugin import LDAPPlugin
LDAP_SETTING = {
    'mode': 'ad',
    'server': 'my.domain.controller',
    'base_dn': 'ou=Users,dc=domain,dc=com'
}
auth.register_plugin(LDAPPlugin(**LDAP_SETTINGS))

OAuth2 com Google (testado OK)

from py4web.utils.auth_plugins.oauth2google import OAuth2Google # TESTED
auth.register_plugin(OAuth2Google(
    client_id=CLIENT_ID,
    client_secret=CLIENT_SECRET,
    callback_url='auth/plugin/oauth2google/callback'))

O ID de cliente e segredo do cliente deve ser fornecido pelo Google.

OAuth2 com Facebook (testado OK)

from py4web.utils.auth_plugins.oauth2facebook import OAuth2Facebook # UNTESTED
auth.register_plugin(OAuth2Facebook(
    client_id=CLIENT_ID,
    client_secret=CLIENT_SECRET,
    callback_url='auth/plugin/oauth2google/callback'))

O ID de cliente e segredo do cliente deve ser fornecido pelo Facebook.

Etiquetas e permissões

O Py4web não tem o conceito de grupos como web2py. A experiência mostrou que, enquanto esse mecanismo é poderoso ele sofre de dois problemas: é um exagero para a maioria dos aplicativos, e não é suficiente flexível para aplicativos muito complexos. Py4web fornece um mecanismo de marcação de uso geral que permite ao desenvolvedor tag qualquer registro de qualquer tabela, verificar a existência de marcas, bem como a verificação de registros contendo uma tag. associação de grupo pode ser considerado um tipo de tag que se aplicam aos usuários. As permissões também pode ser tags. Desenvolvedor é livre para criar sua própria lógica no topo do sistema de marcação.

Para usar o sistema de marcação, você precisa criar um objeto para marcar uma tabela:

groups = Tags(db.auth_user)

Então você pode adicionar uma ou mais marcas de registros da tabela, bem como remover existente tags:

groups.add(user.id, 'manager')
groups.add(user.id, ['dancer', 'teacher'])
groups.remove(user.id, 'dancer')

Aqui, o caso de uso é o controle de acesso baseado em grupo, onde o desenvolvedor primeiro verifica se um usuário é um membro do «grupo` manager”`, se o usuário não é um administrador (ou ninguém está logado) redirecionamentos py4web ao `` “não autorizada url”``. Se o usuário estiver no grupo correto, então manager Olá “py4web exibe:

@action('index')
@action.uses(auth.user)
def index():
    if not 'manager' in groups.get(auth.get_user()['id']):
        redirect(URL('not_authorized'))
    return 'hello manager'

Aqui o desenvolvedor consulta o banco de dados para todos os registros que têm a tag desejada (s):

@action('find_by_tag/{group_name}')
@action.uses(db)
def find(group_name):
    users = db(groups.find([group_name])).select(orderby=db.auth_user.first_name | db.auth_user.last_name)
    return {'users': users}

Deixamos para você como um exercício para criar um dispositivo elétrico `` has_membership`` para permitir a seguinte sintaxe:

@action('index')
@action.uses(has_membership(groups, 'teacher'))
def index():
    return 'hello teacher'

Important: Tags are automatically hierarchical. For example, if a user has a group tag ‘teacher/high-school/physics’, then all the following searches will return the user:

  • `` Groups.find ( “professor /-ensino médio / física”) ``

  • `` Groups.find ( “professor /-colegial”) ``

  • `` Groups.find ( “professor”) ``

This means that slashes have a special meaning for tags. Slashes at the beginning or the end of a tag are optional. All other chars are allowed on equal footing.

Notice that one table can have multiple associated Tags objects. The name groups here is completely arbitrary but has a specific semantic meaning. Different Tags objects are orthogonal to each other. The limit to their use is your creativity.

Por exemplo, você poderia criar um grupos de mesa:

db.define_table('auth_group', Field('name'), Field('description'))

e Tags:

groups = Tags(db.auth_user)
permissions = Tags(db.auth_groups)

Em seguida, crie um grupo zapper, dar-lhe uma permissão, e tornar um membro do usuário do grupo:

zap_id = db.auth_group.insert(name='zapper', description='can zap database')
permissions.add(zap_id, 'zap database')
groups.add(user.id, 'zapper')

E você pode verificar se há uma permissão de utilizador através de uma junção explícita:

@action('zap')
@action.uses(auth.user)
def zap():
    user = auth.get_user()
    permission = 'zap database'
    if db(permissions.find(permission))(
          db.auth_group.name.belongs(groups.get(user['id']))
          ).count():
        # zap db
        return 'database zapped'
    else:
        return 'you do not belong to any group with permission to zap db'

Aviso aqui `` permissions.find (permissão) `` gera uma consulta para todos os grupos com a permissão e que ainda filtro desses grupos para aqueles do utilizador actual é membro da. Contamos eles e se encontrarmos qualquer, então o usuário tem a permissão.