diff --git a/aulas/06.md b/aulas/06.md index 817784b6..bc1feb4c 100644 --- a/aulas/06.md +++ b/aulas/06.md @@ -432,7 +432,7 @@ def user(session): session.commit() session.refresh(user) - user.clean_password = 'testtest' + user.clean_password = password return user ``` diff --git a/aulas/08.md b/aulas/08.md index 4d78d030..58857583 100644 --- a/aulas/08.md +++ b/aulas/08.md @@ -110,7 +110,7 @@ def user(session): session.commit() session.refresh(user) - user.clean_password = 'testtest' + user.clean_password = password return user @@ -124,7 +124,7 @@ def other_user(session): session.commit() session.refresh(user) - user.clean_password = 'testtest' + user.clean_password = password return user ``` diff --git a/codigo_das_aulas/06/tests/conftest.py b/codigo_das_aulas/06/tests/conftest.py index 8eef2c69..a6260e73 100644 --- a/codigo_das_aulas/06/tests/conftest.py +++ b/codigo_das_aulas/06/tests/conftest.py @@ -62,6 +62,7 @@ def mock_db_time(): @pytest.fixture def user(session): + password = 'testtest' user = User( username='Teste', email='teste@test.com', @@ -71,7 +72,7 @@ def user(session): session.commit() session.refresh(user) - user.clean_password = 'testtest' + user.clean_password = password return user diff --git a/codigo_das_aulas/07/tests/conftest.py b/codigo_das_aulas/07/tests/conftest.py index d4ccbb22..b5af74a0 100644 --- a/codigo_das_aulas/07/tests/conftest.py +++ b/codigo_das_aulas/07/tests/conftest.py @@ -63,16 +63,17 @@ def mock_db_time(): @pytest.fixture def user(session): + password = 'testtest' user = User( username='Teste', email='teste@test.com', - password=get_password_hash('testtest'), + password=get_password_hash(password), ) session.add(user) session.commit() session.refresh(user) - user.clean_password = 'testtest' + user.clean_password = password return user diff --git a/codigo_das_aulas/08/tests/conftest.py b/codigo_das_aulas/08/tests/conftest.py index 38645d93..c5dccc66 100644 --- a/codigo_das_aulas/08/tests/conftest.py +++ b/codigo_das_aulas/08/tests/conftest.py @@ -50,7 +50,7 @@ def user(session): session.commit() session.refresh(user) - user.clean_password = 'testtest' + user.clean_password = password return user @@ -85,7 +85,7 @@ def other_user(session): session.commit() session.refresh(user) - user.clean_password = 'testtest' + user.clean_password = password return user diff --git a/codigo_das_aulas/09/tests/conftest.py b/codigo_das_aulas/09/tests/conftest.py index c94b6929..7afa3eec 100644 --- a/codigo_das_aulas/09/tests/conftest.py +++ b/codigo_das_aulas/09/tests/conftest.py @@ -71,7 +71,7 @@ def user(session): session.commit() session.refresh(user) - user.clean_password = 'testtest' + user.clean_password = password return user @@ -85,7 +85,7 @@ def other_user(session): session.commit() session.refresh(user) - user.clean_password = 'testtest' + user.clean_password = password return user diff --git a/codigo_das_aulas/10/tests/conftest.py b/codigo_das_aulas/10/tests/conftest.py index 9ce5f1e6..840d573e 100644 --- a/codigo_das_aulas/10/tests/conftest.py +++ b/codigo_das_aulas/10/tests/conftest.py @@ -77,7 +77,7 @@ def user(session): session.commit() session.refresh(user) - user.clean_password = 'testtest' + user.clean_password = password return user @@ -91,7 +91,7 @@ def other_user(session): session.commit() session.refresh(user) - user.clean_password = 'testtest' + user.clean_password = password return user diff --git a/codigo_das_aulas/11/tests/conftest.py b/codigo_das_aulas/11/tests/conftest.py index 9ce5f1e6..840d573e 100644 --- a/codigo_das_aulas/11/tests/conftest.py +++ b/codigo_das_aulas/11/tests/conftest.py @@ -77,7 +77,7 @@ def user(session): session.commit() session.refresh(user) - user.clean_password = 'testtest' + user.clean_password = password return user @@ -91,7 +91,7 @@ def other_user(session): session.commit() session.refresh(user) - user.clean_password = 'testtest' + user.clean_password = password return user diff --git a/codigo_das_aulas/12/tests/conftest.py b/codigo_das_aulas/12/tests/conftest.py index 9ce5f1e6..65ff8db5 100644 --- a/codigo_das_aulas/12/tests/conftest.py +++ b/codigo_das_aulas/12/tests/conftest.py @@ -77,7 +77,7 @@ def user(session): session.commit() session.refresh(user) - user.clean_password = 'testtest' + user.clean_password = password return user diff --git a/slides/brutos/aula_08.md b/slides/brutos/aula_08.md index 85b7f38a..22c870d0 100644 --- a/slides/brutos/aula_08.md +++ b/slides/brutos/aula_08.md @@ -130,7 +130,7 @@ def user(session): session.commit() session.refresh(user) - user.clean_password = 'testtest' + user.clean_password = password return user ``` @@ -153,7 +153,7 @@ def other_user(session): session.commit() session.refresh(user) - user.clean_password = 'testtest' + user.clean_password = password return user ``` diff --git a/slides/html/aula_08.html b/slides/html/aula_08.html index d94f66eb..558ea53f 100644 --- a/slides/html/aula_08.html +++ b/slides/html/aula_08.html @@ -30,13 +30,13 @@ /* Code blok */div#\:\$p>svg>foreignObject>section .hljs-bullet{color:var(--text)}div#\:\$p>svg>foreignObject>section .hljs-comment{color:var(--muted)}div#\:\$p>svg>foreignObject>section .hljs-attr{color:var(--foam)}div#\:\$p>svg>foreignObject>section .hljs-punctuation{color:var(--subtle)}div#\:\$p>svg>foreignObject>section .hljs-string{color:var(--gold)}div#\:\$p>svg>foreignObject>section .hljs-title{color:var(--foam)}div#\:\$p>svg>foreignObject>section .hljs-keyword{color:var(--pine)}div#\:\$p>svg>foreignObject>section .hljs-variable{color:var(--text)}div#\:\$p>svg>foreignObject>section .hljs-literal{color:var(--rose)}div#\:\$p>svg>foreignObject>section .hljs-type{color:var(--love)}div#\:\$p>svg>foreignObject>section .hljs-number{color:var(--gold)}div#\:\$p>svg>foreignObject>section .hljs-built_in{color:var(--love)}div#\:\$p>svg>foreignObject>section .hljs-params{color:var(--iris)}div#\:\$p>svg>foreignObject>section .hljs-symbol{color:var(--foam)}div#\:\$p>svg>foreignObject>section .hljs-meta{color:var(--subtle)}div#\:\$p>svg>foreignObject>section .hljs-subst{color:var(--subtle)}div#\:\$p>svg>foreignObject>section blockquote{font-size:20px}div#\:\$p>svg>foreignObject>section blockquote p{font-size:20px}div#\:\$p>svg>foreignObject>section blockquote p a{font-size:30px}div#\:\$p>svg>foreignObject>section div.mermaid{text-align:center}div#\:\$p>svg>foreignObject>section img[alt~=center]{display:block;margin:0 auto}div#\:\$p>svg>foreignObject>section .columns{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:calc(var(--marpit-root-font-size, 1rem) * 1)}div#\:\$p>svg>foreignObject>section .mermaid{font-size:10px}div#\:\$p>svg>foreignObject>section section.mermaid{--marpit-root-font-size:10px} -/* @theme iyyh2866o7dw2fbrrlm9ub03n0zaylvan8iszae7enf */div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]{columns:initial!important;display:block!important;padding:0!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]:after,div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]:before,div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=content]:after,div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=content]:before{display:none!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container]{all:initial;display:flex;flex-direction:row;height:100%;overflow:hidden;width:100%}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container][data-marpit-advanced-background-direction=vertical]{flex-direction:column}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background][data-marpit-advanced-background-split]>div[data-marpit-advanced-background-container]{width:var(--marpit-advanced-background-split,50%)}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background][data-marpit-advanced-background-split=right]>div[data-marpit-advanced-background-container]{margin-left:calc(100% - var(--marpit-advanced-background-split, 50%))}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container]>figure{all:initial;background-position:center;background-repeat:no-repeat;background-size:cover;flex:auto;margin:0}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container]>figure>figcaption{position:absolute;border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;white-space:nowrap;width:1px}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=content],div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=pseudo]{background:transparent!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=pseudo],div#\:\$p>svg[data-marpit-svg]>foreignObject[data-marpit-advanced-background=pseudo]{pointer-events:none!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background-split]{width:100%;height:100%}
+/* @theme 0wjssjy7v0oa1g0tki0a0qafwu1mjnl8p7rm10qyizubm */div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]{columns:initial!important;display:block!important;padding:0!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]:after,div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]:before,div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=content]:after,div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=content]:before{display:none!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container]{all:initial;display:flex;flex-direction:row;height:100%;overflow:hidden;width:100%}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container][data-marpit-advanced-background-direction=vertical]{flex-direction:column}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background][data-marpit-advanced-background-split]>div[data-marpit-advanced-background-container]{width:var(--marpit-advanced-background-split,50%)}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background][data-marpit-advanced-background-split=right]>div[data-marpit-advanced-background-container]{margin-left:calc(100% - var(--marpit-advanced-background-split, 50%))}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container]>figure{all:initial;background-position:center;background-repeat:no-repeat;background-size:cover;flex:auto;margin:0}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=background]>div[data-marpit-advanced-background-container]>figure>figcaption{position:absolute;border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;white-space:nowrap;width:1px}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=content],div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=pseudo]{background:transparent!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background=pseudo],div#\:\$p>svg[data-marpit-svg]>foreignObject[data-marpit-advanced-background=pseudo]{pointer-events:none!important}div#\:\$p>svg>foreignObject>section[data-marpit-advanced-background-split]{width:100%;height:100%}

Tornando o sistema de autenticação robusto

https://fastapidozero.dunossauro.com/08/

-
+

Objetivos da Aula

  • Testar os casos de autenticação de forma correta
  • @@ -46,13 +46,13 @@

    Objetivos da Aula

  • Introduzir geração de modelos automática com factory-boy
-
+

Testes de autorização

Parte 1

-
+

Garantir que o user faça somente o que pode

@router.put('/{user_id}', response_model=UserPublic)
 def update_user(
@@ -69,7 +69,7 @@ 

Garantir que o user fa

Não deve ser possível alterar via PUT os dados que não são seus

-
+
def test_update_user_with_wrong_user(client, user, token):
     response = client.put(
         f'/users/{user.id + 1}',
@@ -85,7 +85,7 @@ 

Garantir que o user fa

Na ultima aula fizemos algo parecido com isso!

-
+

O problema dessa abordagem

O uso do +1 nos leva a algumas discussões interessantes:

    @@ -97,7 +97,7 @@

    O problema dessa abordagem

  • precisamos adicionar um novo user ao cenário de teste
-
+

Criando modelos Users sob demanda

Para fazer a criação de users de forma mais intuitiva e sem a preocupação de valores repetidos, podemos usar uma "fábrica" de usuários.

Isso pode ser feito com uma biblioteca chamada factory-boy:

@@ -107,7 +107,7 @@

Criando modelos Users so

Fábrica é um padrão de projeto de construção de objetos.

-
+

O Factory-boy

#conftest.py
 import factory
@@ -123,7 +123,7 @@ 

O Factory-boy

password = factory.LazyAttribute(lambda obj: f'{obj.username}@example.com')
-
+

O uso do factory-boy + fixture

@@ -139,7 +139,7 @@

O uso do factory-boy + fixture

session.commit() session.refresh(user) - user.clean_password = 'testtest' + user.clean_password = password return user @@ -157,14 +157,14 @@

O uso do factory-boy + fixture

session.commit() session.refresh(user) - user.clean_password = 'testtest' + user.clean_password = password return user
-
+

Alterando o teste de put para esse cenário

def test_update_user_with_wrong_user(client, other_user, token):
     response = client.put(
@@ -180,7 +180,7 @@ 

Alterando o teste de pu assert response.json() == {'detail': 'Not enough permissions'}

-
+

Criando um teste de DELETE para o cenário

def test_delete_user_wrong_user(client, other_user, token):
     response = client.delete(
@@ -191,13 +191,13 @@ 

Criando um teste de DELE assert response.json() == {'detail': 'Not enough permissions'}

-
+

Expiração do token

Parte 2

-
+

Sobre o tempo do token

Quando geramos o token, ele tem a claim 'exp' que é ferente a validade do token.

@@ -219,7 +219,7 @@

Sobre o tempo do token

-
+

O sistema do token

sequenceDiagram @@ -233,7 +233,7 @@

O sistema do token

Server->>Cliente: Retorna a operação
-
+

O tempo de duração

sequenceDiagram @@ -245,13 +245,13 @@

O tempo de duração

Esse fluxo ainda não está implementado

-
+

Precisamos "viajar no tempo"

Para isso temos a "arma do tempo" o freezegun, uma biblioteca que ajuda a pausar o tempo durante os testes:

poetry add freezegun
 
-
+

Usando o freezegun

from freezegun import freeze_time
 
@@ -267,7 +267,7 @@ 

Usando o freezegun

token = response.json()['access_token']
-
+

Viajando no tempo

def test_token_expired_after_time(client, user):
     # ...
@@ -285,7 +285,7 @@ 

Viajando no tempo

assert response.json() == {'detail': 'Could not validate credentials'}
-
+

A validação da expiração

def get_current_user(
     try:
@@ -302,13 +302,13 @@ 

A validação da expiraç raise credentials_exception

-
+

Problemas de autenticação

Parte 4

-
+

Algumas coisas não foram cobertas

Os nossos testes não cobrem os casos onde temos:

    @@ -316,7 +316,7 @@

    Algumas coisas não foram cobert
  • Email inexistente
-
+

Testando a senha incorreta

def test_token_wrong_password(client, user):
     response = client.post(
@@ -327,7 +327,7 @@ 

Testando a senha incorreta

assert response.json() == {'detail': 'Incorrect email or password'}
-
+

Testando o user inexistente

def test_token_inexistent_user(client):
     response = client.post(
@@ -338,13 +338,13 @@ 

Testando o user inexistente

assert response.json() == {'detail': 'Incorrect email or password'}
-
+

Refresh do token

Parte 5

-
+

O que acontece quando o exp vence?

É necessario que o cliente renove o token de tempos em tempos para que ele não perca a validade e possa continuar usando a aplicação sem logar novamente.

# fast_zero/routes/auth.py
@@ -358,7 +358,7 @@ 

O que acontece quando o exp vence?return {'access_token': new_access_token, 'token_type': 'bearer'}

-
+

O teste para o refresh

Ver se o refresh faz mesmo refresh :)

def test_refresh_token(client, user, token):
@@ -375,7 +375,7 @@ 

O teste para o refresh

assert data['token_type'] == 'bearer'
-
+

Testando o fluxo de refresh

Não se pode dar refresh depois que o token fica inválido

def test_token_expired_dont_refresh(client, user):
@@ -396,15 +396,15 @@ 

Testando o fluxo de refresh

assert response.json() == {'detail': 'Could not validate credentials'}
-
+

Exercício

O endpoint de PUTusa dois users criados na base de dados, porém, até o momento ele cria um novo user no teste via request na API por falta de uma fixture como other_user. Atualize o teste para usar essa nova fixture.

-
+

Quiz

Não esqueça de responder o quiz dessa aula!

-
+

Commit

git add .
 git commit -m "Implementando o reresh do token e testes de autorização"
diff --git a/slides/pdf/aula_08.pdf b/slides/pdf/aula_08.pdf
index 3c7a6af6..48fa9fb8 100644
Binary files a/slides/pdf/aula_08.pdf and b/slides/pdf/aula_08.pdf differ