JWT + Laravel para autenticação de serviços

O que é JWT?

JWT(JSON WEB TOKEN) é um token auto-contido e baseado no padrão RFC7519 da W3C, formado por um header, um payload e um secret que são encriptados e enviados como uma string. Usado para autenticação
entre serviços e podendo ser utilizados de várias outras formas, como por exemplo
autenticação de usuários mesmo em ambientes não seguros(http).

O que é o Laravel?

Atualmente umas das framework mais populares para PHP. O LARAVEL agiliza o desenvolvimento, fornecendo vários métodos prontos, um gerenciamento de dependências simples e intuitivo através do composer, o ORM através do Eloquent que faz o uso de query’s sql não serem uma grande dor de cabeça ao desenvolvedor e várias outras ferramentas de auxílio ao desenvolvimento.

Instalando a dependência do JWT no Laravel

Para começar devemos instalar a dependência do JWT no nosso projeto Laravel. Para a instalarmos o JWT devemos acessar o cmd / bash e digitar:

composer require tymon/jwt-auth

Agora publicamos o pacote através do comando:

artisan vendor:publish -- provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

E logo após utilizamos o comando para gerar um hash para o JWT:

php artisan jwt:secret

Esta informação fica armazenada na constante “JWT_SECRET” no arquivo .env, na raiz da pasta do projeto.

As configurações referentes ao token encontram-se no arquivo ‘jwt.php’ na pasta config. Neste arquivo é possível alterar configurações, como a validade do token(TTL) e tempo de refresh do mesmo.

JWT instalado e agora?

Agora com o JWT instalado podemos utilizar o middleware do pacote tymon/jwt-auth que por padrão é chamado como ‘jwt.auth’, para isso basta o adicionarmos as rotas que desejarmos:

Route::get('admin/profile', function () {
//
})->middleware('jwt.auth');
// ROUTE GROUP
Route::group(['middleware' => ['jwt.auth']], function () {
//
});

Ou diretamente no controlador através do construtor:

class AlunoController extends ApiBaseController
{
public function __construct()
{
$this->middleware('jwt.auth');
$this->repository = new AlunoRepository();
}
public function index()
{
return $this->repository->get();
}
}

Qualquer usuário que não esteja autenticado receberá um erro 401 ao tentar acesso às rotas registradas com o middleware do JWT:

Retorno do Laravel ao acessar rota sem estar autenticado

Como autenticar usuário com JWT?

Agora para acessarmos a rota, nossa classe Users(ou a classe que faz a autenticação de usuários) deve implementar a interface JWTSubject. Esta interface obrigará a implementação dos métodos getJWTIdentifier() e getJWTCustomClaims().

No método getJWTIdentifier() passamos a chave primária do modelo:

public function getJWTIdentifier()
{
// TODO: Implement getJWTIdentifier() method.
return $this->getKey();
}

Já o método getJWTCustomClaims() é utilizado para retornarmos dados no payload do token(assim podendo ter informações que serão utilizadas na outra ponta após ser desencriptada). No exemplo está sendo retornado o email da classe User padrão do Laravel, devemos nos atentar que o custom claims deve retorna um array:

public function getJWTCustomClaims()
{
// TODO: Implement getJWTCustomClaims() method.
return [
'email' => $this->email
];
}

E agora fazemos a autenticação do usuário. Vou citar algumas formas de como retornamos o token para o usuário, assim devemos definir qual a forma que melhor irá atender-nos e estarmos cientes de que não existem apenas estas formas de realizarmos a autenticação.

1ª forma:

// FORMA MAIS DIRETA PARA AUTENTICAÇÃO
public function login($array){
// COMO ESTOU UTILIZANDO O MIDDLEWARE SOMENTE NAS ROUTAS DE API, FOI DEFINIDO ESPECIFICAMENTE O GUARD "api"
$user = auth('api')->attempt(
['email' => $array['email'], 'password' => $array['password']]
);


return response()->json($user);
}

2ª forma:

public function login($array) {
if (!Auth::attempt(['email' => $array['email'], 'password' => $array['password']])) {
throw new HttpResponseException(response()->json(['Usuário ou senha incorreto.'], 400));
}
$user = JWTAuth::fromUser(Auth::user());
return response()->json($user);
}

Apenas como informação adicional também é possível alterar configurações do token diretamente no código, como por exemplo a validade:

public function login($array){
// TOKEN COM TTL DE UMA SEMANA
$user = auth('api')->setTTL(Carbon::now()->addweek()->timestamp)->attempt(
['email' => $array['email'], 'password' => $array['password']]
);

return response()->json($user);
}

Exemplo da classe User :

class User extends Authenticatable implements JWTSubject
{
use Notifiable;
protected $primaryKey = 'id'; /**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function getJWTIdentifier()
{
// TODO: Implement getJWTIdentifier() method.
return $this->getKey();
}
public function getJWTCustomClaims()
{
// TODO: Implement getJWTCustomClaims() method.
return [
'email' => $this->email
];
}
public function login($array){
if (!Auth::attempt(['email' => $array['email'], 'password' => $array['password']])) {
throw new HttpResponseException(response()->json(['Usuário ou senha incorreto.'], 400));
}
$user = JWTAuth::fromUser(Auth::user());
return response()->json($user);
}
}

O retorno do da requisicao ao Laravel será uma similar a esse:

O token pode ser verificado através do site https://jwt.io. Ao colocarmos o token na parte “enconded” ele inicialmente falhará na assinatura:

Para verificarmos a assinatura pasta adicionarmos o “JWT_SECRET” que se encontra no .env do nosso projeto Laravel no campo “your-256-bit-secret” e caso o esteja válido, ficará como na imagem:

Também é exibido o email que foi colocado no método getCustomClaims, as outras informações(iss, iat, etc…) têm suas exibições definidas no jwt.php, na seção “required_claims”, porém não sendo aconselhável que estes campos sejam alterados(apenas para fins de informação).

Conclusão

Ainda existem várias outras funções do pacote tymon/jwt-auth, podendo ser consultada através da documentação https://github.com/tymondesigns/jwt-auth. Após gerado o token pode ser consumido por várias outras linguagens fornecendo uma forma segura de acesso à api. Espero ter sido de ajuda a todos e bons estudos! =)

--

--