91 lines
2.9 KiB
Erlang
91 lines
2.9 KiB
Erlang
-module(handler_refresh).
|
|
-include("records.hrl").
|
|
|
|
-export([init/2]).
|
|
|
|
init(Req, Opts) ->
|
|
handle(Req, Opts).
|
|
|
|
handle(Req, _Opts) ->
|
|
case cowboy_req:method(Req) of
|
|
<<"POST">> ->
|
|
{ok, Body, Req1} = cowboy_req:read_body(Req),
|
|
case jsx:decode(Body, [return_maps]) of
|
|
#{<<"refresh_token">> := RefreshToken} ->
|
|
case validate_refresh_token(RefreshToken) of
|
|
{ok, UserId} ->
|
|
case core_user:get_by_id(UserId) of
|
|
{ok, User} ->
|
|
% Генерируем новые токены
|
|
NewToken = logic_auth:generate_jwt(User#user.id, User#user.role),
|
|
{NewRefreshToken, ExpiresAt} = logic_auth:generate_refresh_token(User#user.id),
|
|
|
|
% Сохраняем новый refresh token
|
|
save_refresh_token(User#user.id, NewRefreshToken, ExpiresAt),
|
|
|
|
% Удаляем старый refresh token
|
|
delete_refresh_token(RefreshToken),
|
|
|
|
Response = #{
|
|
token => NewToken,
|
|
refresh_token => NewRefreshToken
|
|
},
|
|
send_json(Req1, 200, Response);
|
|
{error, not_found} ->
|
|
send_error(Req1, 401, <<"User not found">>)
|
|
end;
|
|
{error, expired} ->
|
|
send_error(Req1, 401, <<"Refresh token expired">>);
|
|
{error, invalid} ->
|
|
send_error(Req1, 401, <<"Invalid refresh token">>)
|
|
end;
|
|
_ ->
|
|
send_error(Req1, 400, <<"Missing refresh_token">>)
|
|
end;
|
|
_ ->
|
|
send_error(Req, 405, <<"Method not allowed">>)
|
|
end.
|
|
|
|
validate_refresh_token(Token) ->
|
|
case get_session_by_token(Token) of
|
|
{ok, Session} ->
|
|
% Проверяем срок действия
|
|
Now = calendar:universal_time(),
|
|
case Session#session.expires_at > Now of
|
|
true -> {ok, Session#session.user_id};
|
|
false -> {error, expired}
|
|
end;
|
|
{error, not_found} ->
|
|
{error, invalid}
|
|
end.
|
|
|
|
get_session_by_token(Token) ->
|
|
Match = #session{token = Token, type = refresh, _ = '_'},
|
|
case mnesia:dirty_match_object(Match) of
|
|
[] -> {error, not_found};
|
|
[Session] -> {ok, Session}
|
|
end.
|
|
|
|
save_refresh_token(UserId, Token, ExpiresAt) ->
|
|
Session = #session{
|
|
token = Token,
|
|
user_id = UserId,
|
|
expires_at = ExpiresAt,
|
|
type = refresh
|
|
},
|
|
mnesia:dirty_write(Session).
|
|
|
|
delete_refresh_token(Token) ->
|
|
Match = #session{token = Token, type = refresh, _ = '_'},
|
|
case mnesia:dirty_match_object(Match) of
|
|
[] -> ok;
|
|
[Session] -> mnesia:dirty_delete_object(Session)
|
|
end.
|
|
|
|
send_json(Req, Status, Data) ->
|
|
Body = jsx:encode(Data),
|
|
cowboy_req:reply(Status, #{<<"content-type">> => <<"application/json">>}, Body, Req).
|
|
|
|
send_error(Req, Status, Message) ->
|
|
Body = jsx:encode(#{error => Message}),
|
|
cowboy_req:reply(Status, #{<<"content-type">> => <<"application/json">>}, Body, Req). |