Next.js: O Guia Complete para Autenticação

Image for post
Image for post

Créditos da Imagem por Kai Pilger

Créditos

Neste guia, você aprenderá como implementar a autenticação em um aplicativo Next.js. Abordarei autenticação de cliente, páginas autenticadas renderizadas no servidor, rotas de API autenticadas, rotas protegidas e redirecionamentos.

O serviço de autenticação será implementado com AWS Amplify, mas as ideias e estratégias abordadas aqui funcionarão para qualquer serviço de autenticação como Auth0 / Okta ou mesmo uma implementação de back-end personalizada, desde que forneça uma maneira de gerenciar sessões no cliente e servidor.

O código para este projeto está localizado aqui . O vídeo passo a passo está aqui.

Visão geral do Next.js

Next.js combina a renderização do lado do cliente com HTML pré-renderizado na forma de páginas estáticas e renderizadas pelo servidor. O framework também deixa muito fácil a criação de APIs com rotas de API.

Ao executar uma compilação, o framework determinará se uma página deve ser gerada estaticamente ou se deve ser renderizada pelo servidor. Por padrão, todas as páginas são geradas estaticamente, a menos que a página esteja usando a função getServerSideProps para passar props para a página. Além disso, todas as rotas de API serão, por padrão, renderizadas pelo servidor.

Conceitos de autenticação Next.js

Ao trabalhar em um aplicativo Next.js, você normalmente quer tirar proveito de todos esses recursos e fazer com que suas APIs funcionem perfeitamente com o framework (cliente e servidor). O problema é que, geralmente, não é fácil acessar com segurança a sessão do usuário no cliente e no servidor.

Neste guia, mostrarei como habilitar a autenticação e autorização do usuário para implementar o seguinte:

  1. Autenticação de cliente
  2. Acessando a sessão do usuário no cliente
  3. Rotas de cliente protegidas
  4. Redirecionamentos do lado do cliente
  5. Acessando a sessão do usuário em uma rota do lado do servidor ( getServerSideProps)
  6. Rotas de servidor protegidas ( getServerSideProps)
  7. Redirecionamentos do lado do servidor ( getServerSideProps)
  8. Acessando a sessão do usuário em uma rota de API
  9. Login social (OAuth)
  10. Implantar o aplicativo usando o componente Next.js Serverless

Começando

Para começar, primeiro crie um novo aplicativo Next.js:

npx create-next-app next-authentication

Em seguida, mude para o novo diretório e instale as dependências:

cd next-authentication
npm install aws-amplify @aws-amplify/ui-react emotion

Inicialize um novo projeto Amplify:

amplify init> Choose defaults when prompted

Se você ainda não instalou e configurou o Amplify CLI, veja este vídeo para uma explicação completa.

Adicione o serviço de autenticação:

amplify add auth? Do you want to use the default authentication and security configuration? Default configuration
? How do you want users to be able to sign in? Username
? Do you want to configure advanced settings? No, I am done.

Em seguida, implante o serviço de autenticação:

amplify push --y

Ativando Amplify SSR

Para ativar o suporte ao Amplify SSR, abra pages/_app.js e adicione o seguinte na parte superior do arquivo:

import Amplify from 'aws-amplify'
import config from '../src/aws-exports'
Amplify.configure({
...config,
ssr: true
})

🔥 Definindo ssrcomo true é tudo o que você precisa fazer para tornar seu aplicativo Amplify compatível com SSR.

Criação da rota de autenticação / perfil

Em seguida, crie um novo arquivo no diretório de pages denominado profile.js .

Aqui, vamos habilitar a autenticação usando o componente withAuthenticator. Este componente criará um fluxo de autenticação do usuário, permitindo que um usuário se inscreva com MFA e faça login.

Neste arquivo, adicione o seguinte código:

// pages/profile.js
import { useState, useEffect } from 'react'
import { Auth } from 'aws-amplify'
import { withAuthenticator, AmplifySignOut } from '@aws-amplify/ui-react'
function Profile() {
const [user, setUser] = useState(null)
useEffect(() => {
// Acessa a sessão do usuário no cliente
Auth.currentAuthenticatedUser()
.then(user => {
console.log("User: ", user)
setUser(user)
})
.catch(err => setUser(null))
}, [])
return (
<div>
{ user && <h1>Welcome, {user.username}</h1> }
<AmplifySignOut />
</div>
)
}
export default withAuthenticator(Profile)

Por fim, atualize pages/_app.js para adicionar um pouco de navegação entre as páginas:

import '../styles/globals.css'
import Link from 'next/link'
import { css } from 'emotion'
import Amplify from 'aws-amplify'
import config from '../src/aws-exports'
Amplify.configure({
...config,
ssr: true
})
export default function MyApp({ Component, pageProps }) {
return (
<div>
<nav className={navStyle}>
<Link href="/">
<span className={linkStyle}>Home</span>
</Link>
<Link href="/profile">
<span className={linkStyle}>Profile</span>
</Link>
</nav>
<Component {...pageProps} />
</div>
)
}
const linkStyle = css`
margin-right: 20px;
cursor: pointer;
`
const navStyle = css`
display: flex;
`

Opcional — Estilo do componente

Você pode configurar o estilo do componente de autenticação. Por exemplo, para tentar combinar o esquema de cor azul que acompanha o projeto inicial de Next.js, você pode adicionar o seguinte na parte inferior de styles/globals.css :

:root {
--amplify-primary-color: #0083e8;
--amplify-primary-tint: #006ec2;
--amplify-primary-shade: #006ec2;
}

Criar uma conta e fazer login

Agora que a rota de perfil foi criada, vamos testá-la criando uma nova conta e fazendo login.

npm run dev

Clique aqui para obter mais maneiras de personalizar o componente withAuthenticator.

Você deve conseguir navegar para a rota /profile para criar uma conta e fazer login.

Usando a classe Auth diretamente

Se você quer construir seu próprio fluxo de autenticação personalizada, você também pode aproveitar a classe Auth que tem mais de 30 métodos para gerenciar o estado da autenticação do usuário, incluindo métodos, como signUp, confirmSignUp, signIn, e forgotPassword.

Acessando a sessão do usuário em uma rota SSR

Agora que os usuários podem fazer o login, vamos criar uma nova rota para testar o SSR.

Crie uma nova rota chamada /protected.js no diretório de páginas.

Aqui, queremos ter uma rota que autentique o usuário no servidor e retorne uma mensagem de sucesso ou de erro com base no estado de autenticação do usuário.

// pages/protected.jsimport { withSSRContext } from 'aws-amplify'function Protected({ authenticated, username }) {
if (!authenticated) {
return <h1>Not authenticated</h1>
}
return <h1>Hello {username} from SSR route!</h1>
}
export async function getServerSideProps(context) {
const { Auth } = withSSRContext(context)
try {
const user = await Auth.currentAuthenticatedUser()
console.log('user: ', user)
return {
props: {
authenticated: true, username: user.username
}
}
} catch (err) {
return {
props: {
authenticated: false
}
}
}
}
export default Protected

Em seguida, atualize a navegação em pages/_app.js com um link para a nova rota:

<Link href="/protected">
<span className={linkStyle}>Protected route</span>
</Link>

Agora, quando você estiver conectado, perceberá que poderá acessar o usuário autenticado no método getServerSideProps. Você também deve ver o objeto de usuário printado no terminal.

Isso é feito usando a função withSSRContext da biblioteca aws-amplify que retorna o objeto Auth e com isso, chamamos o Auth.currentAuthenticatedUser(). Ao obter acesso à classe Auth dessa maneira, o Amplify lerá automaticamente o objeto de solicitação da requisição (context) e dará a você acesso à sessão do usuário conectado em ambas as rotas de API e também em rotas SSR.

Acessando a sessão do usuário em uma rota de API

Nesta rota de API, queremos acessar a sessão do usuário e retornar null para um usuário que não está autenticado ou o nome de usuário para um usuário que está autenticado.

Para fazer isso, crie um novo arquivo em pages/api chamado check-user.js :

// pages/api/check-user.js
import Amplify, { withSSRContext } from 'aws-amplify'
import config from "../../src/aws-exports.js"
// Configuração necessária para habilitar o Amplify SSR em rotas de API
Amplify.configure({ ...config, ssr: true })
export default async (req, res) => {
const { Auth } = withSSRContext({ req })
try {
const user = await Auth.currentAuthenticatedUser()
res.json({ user: user.username })
} catch (err) {
res.statusCode = 200
res.json({ user: null })
}
}

Ao navegar ou tentar acessar /api/check-user, você perceberá que o objeto de usuário está disponível quando você está autenticado e indisponível quando você não está autenticado.

Redirecionamento do lado do cliente

Freqüentemente, você irá detectar se um usuário está conectado e permitir o acesso ou redirecioná-lo com base na sessão ou suas credenciais.

Para fazer isso, você pode usar o gancho withRouther do Next.js, para navegar programaticamente com o usuário com base no estado de sua sessão.

Crie um novo arquivo no diretório pages chamado protected-client-route.js.

Aqui, adicione o seguinte código:

import { useState, useEffect } from 'react'
import { Auth } from 'aws-amplify'
import { useRouter } from 'next/router'
function ProtectedClient() {
const [user, setUser] = useState(null)
const router = useRouter()
useEffect(() => {
Auth.currentAuthenticatedUser()
.then(user => setUser(user))
// Se o usuário não estiver autenticado, redirecione ele para a página `/profile`
.catch(() => router.push('/profile'))
}, [])
if (!user) return null
return <h1>Hello {user.username} from client route!</h1>
}
export default ProtectedClient

Em seguida, adicione um link para esta rota em pages/_app.js :

<Link href="/protected-client-route">
<span className={linkStyle}>Protected client route</span>
</Link>

Se você tentar acessar a rota do cliente protegida, será redirecionado automaticamente para a rota do /profile se não estiver autenticado e se estiver autenticado, terá permissão para ver a página!

Redirecionamentos do lado do servidor

Um dos benefícios do SSR é a capacidade de implementar redirecionamentos do lado do servidor. Usar um redirecionamento do lado do servidor é mais seguro, pois você tem a opção de não renderizar nenhum html.

Abra pages/protected.js e atualize com o seguinte código:

// pages/protected.js
import { withSSRContext } from 'aws-amplify'
function Protected({ username }) {
return <h1>Hello {username} from SSR route!</h1>
}
export async function getServerSideProps({ req, res }) {
const { Auth } = withSSRContext({ req })
try {
const user = await Auth.currentAuthenticatedUser()
return {
props: {
authenticated: true,
username: user.username
}
}
} catch (err) {
res.writeHead(302, { Location: '/profile' })
res.end()
}
return {props: {}}
}
export default Protected

Ao tentar acessar esta rota, você será redirecionado para a rota do /profile se não estiver autenticado.

Login social (OAuth)

Para adicionar login social, execute amplify update auth e escolha Apply default configuration with Social Provider.

A partir daqui, você pode adicionar login social com Google, Facebook ou Amazon.

Depois que o login social for ativado, você poderá conectar os usuários do seu aplicativo usando o seguinte código:

// nome de usuário e password + todos os provedores de OAuth
Auth.federatedSignIn()
// specifying an OAuth provider
<button onClick={() => Auth.federatedSignIn({provider: 'Facebook'})}>Open Facebook</button>
<button onClick={() => Auth.federatedSignIn({provider: 'Google'})}>Open Google</button>
<button onClick={() => Auth.federatedSignIn({provider: 'Amazon'})}>Open Amazon</button>

Implantar o aplicativo Next.js na AWS com o Serverless Framework

Para implantar o aplicativo na AWS usando o Serverless Framework e o Serverless Next Component , primeiro crie um arquivo chamado serverless.yml na raiz do seu aplicativo.

Em seguida, adicione as duas linhas de configuração a seguir (sinta-se à vontade para alterar myNextApp para qualquer nome que você gostaria de usar):

myNextApp:
component: "@sls-next/serverless-component@1.16.0"

Em seguida, implante usando npx:

npx serverless

Se você nunca usou um AWS CLI, terá que configurar suas credenciais AWS. Veja as instruções básicas aqui.

Passo a passo de vídeo

O código final para este projeto está localizado aqui.

Um grande obrigado para Eric Clemmons da equipe do Amplify que liderou este projeto e construiu essa funcionalidade no Amplify.

Para a parte 2, aprenderemos como combinar Auth e Data para realizar o seguinte:

  1. Buscar dados em getStaticPaths para hidratação durante SSG
  2. Fazer chamadas de API autenticadas em rotas de API
  3. Fazer uma solicitação de API autenticada em getServerSideProps

Written by

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store