JSON Web Token es un estándar abierto para crear tokens de acceso basados en el formato JSON. Normalmente se utiliza para pasar datos de autenticación en aplicaciones cliente-servidor. Wikipedia
Cuando se trata de almacenar datos confidenciales en un navegador, solo necesita usar una de las dos opciones disponibles: cookies o localStorage. Aquí todo el mundo elige degustar. Sin embargo, dediqué este artículo a Secret Service, un servicio que se ejecuta sobre D-Bus y está diseñado para almacenar "secretos" en Linux.
El servicio tiene una API que GNOME Keyring usa para almacenar secretos de aplicaciones.
Por qué el servicio secreto
La cuestión es que no recibía el token en el navegador. Estaba escribiendo autenticación de cliente para una aplicación de consola similar a la que se usa en git.
La cuestión de cómo almacenar los detalles surgió de inmediato, ya que no quería obligar a los usuarios a iniciar sesión la próxima vez que se lanzara mi aplicación.
Al principio, había una opción para almacenar el token en un archivo cifrado, pero desapareció de inmediato porque supuse que mis funciones de cifrado y descifrado serían una bicicleta.
Luego pensé en cómo Linux guarda secretos y resultó que se implementan mecanismos similares en otros sistemas operativos.
Como resultado, la contraseña de la cuenta de usuario de Linux servirá como clave de acceso al token.
Arquitectura del Servicio Secreto de un vistazo
La estructura de datos principal del Servicio Secreto es una colección de elementos con atributos y un secreto.
Colección
Esta es una colección de todo tipo de datos de autenticación. El sistema utiliza la colección predeterminada con el alias "predeterminado". Todas las aplicaciones de usuario están escritas en él. Seahorse nos lo mostrará.

Como puede ver, Google Chrome y VSCode se guardan en mi almacenamiento. Mi aplicación también se guardará aquí.
Cada uno de estos registros se denomina artículo.
Elemento
La parte de la colección que almacena atributos y un secreto.
Atributos
Un par de la clave de formulario, valor, que contiene el nombre de la aplicación y sirve para identificar el elemento.

Secreto
, , , .
Secret Service
, flow chart.

« ?» — .
« » — .
« » — .
« API» — .
« » — .
« » — .
Python
Click Framework CLI .
import click, , . . , .
@click.group()
def cli():
pass.
:
$ app login
Email:
Password::
$ app login
Logged in!login
@cli.command(help="Login into your account.")
@click.option(
'--email',
prompt=True,
help='Registered email address.')
@click.option(
'--password',
prompt=True,
hide_input=True,
help='Password provided at registration.'
)
def login(email, password):
pass
if __name__ == '__main__':
cli() login, , email password.
@cli.command , @click.option .
, hide_input .
prompt , lick Framework , .
True False , :
TrueClick Framework . . , WEB API Secret Service, Secret Service API;FalseClick Framework . , , Secret Service.
, prompt_desicion. Secret Service. , Secret Service API .
. , , Click Framework.
, , Click Framework, .
app Click Framework. auth, Auth .
.
├── auth.py
└── app.py
prompt_desicion auth Auth auth.
@cli.command(help="Login into your account.")
@click.option(
'--email',
prompt=auth.prompt_desicion,
help='Registered email address.')
@click.option(
'--password',
prompt=auth.prompt_desicion,
hide_input=True,
help='Password provided at registration.'
)
def login(email, password):
pass
if __name__ == '__main__':
cli()
Python SecreteStorage, Secret Service API.
, Secret Service.
Secret Service API WEB API, prompt_desicion .
requests — HTTP WEB API.
secretstorage — Secret Service API.
json — .
import requests
import secretstorage
import jsonSecrete Storage
class Auth:
def __init__(self, email=None, password=None):
# ,
# Secret Service
self._attributes = {'application': 'MyApp'}
# Dbus
self._connection = secretstorage.dbus_init()
# -
self._collection = secretstorage.collection.get_default_collection(
self._connection
)
#
self._items = self._collection.search_items(self._attributes)
#
self._stored_secret = self.get_stored_secret().
Secret Service self._attributes.
«_»
, . , . , . , , . , .
, . () SecretStorage () . , , self._items .
get_stored_secret, .
class Auth:
def get_stored_secret(self):
for item in self._items:
if item:
return json.loads(item.get_secret())
Item secretstorage, get_secret, .
. .
.
True False — ,
, , : « — False».
class Auth:
def __init__(self, email=None, password=None):
# ,
self.prompt_desicion = False
. , .
class Auth:
def __init__(self, email=None, password=None):
# ,
#
if self._stored_secret:
# token
self.token = self._stored_secret['token']
#
elif email and password:
# WEB API
self.token = self.get_token(email, password)
#
self._valid_secret = {'token': self.token}
# Secret Service
self.set_stored_secret()
else:
# Secret Storage,
#
self.prompt_desicion = True- .
Secret Storage API.
, .
Secret Storage.
Secret Storage API.
, Secret Storage.
, .
, WEB API.
, Secret Storage.
Secret Storage WEB API.
WEB API
class Auth:
def get_token(self, email: str, password: str) -> str:
try:
response = requests.post(
API_URL,
data= {
'email': email,
'passwd': password
})
data = response.json()
except requests.exceptions.ConnectionError:
raise requests.exceptions.ConnectionError()
if response.status_code != 200:
raise requests.exceptions.HTTPError(data['msg'])
return data['data']['token'] API_URL API. , . , POST «email» «passwd».
API , API .
API «msg» . try .
«data».
Secret Storage
class Auth:
def set_stored_secret(self):
self._collection.create_item(
'MyApp',
self._attributes,
bytes((json.dumps(self._valid_secret)), 'utf-8')
)
create_item , .
lick Framework
auth.
from auth import AuthSecret Storage.
auth = Auth().
@cli.command(help="Login into VPN Manager account.")
@click.option(
'--email',
prompt=auth.prompt_desicion,
help='Registered email address.')
@click.option(
'--password',
prompt=auth.prompt_desicion,
hide_input=True,
help='Password provided at registration.'
)login.
def login(email, password):
global auth
try:
#
if auth.prompt_desicion:
# Secret Storage
auth = Auth(email, password)
except Exception:
return click.echo('No API connection')
# , .
click.echo(auth.token)Haga clic en Framework genera ayuda automáticamente. Para hacer esto, necesita las líneas que especifiqué en el parámetro de helpsus decoradores.
$ python app.py
Usage: app.py [OPTIONS] COMMAND [ARGS]...
Options:
--help Show this message and exit.
Commands:
login Login into your account.
Ayuda del comando de inicio de sesión
$ python app.py login --help
Usage: app.py login [OPTIONS]
Login into your account
Options:
--email TEXT Registered email address
--password TEXT Password provided at registration
--help Show this message and exit.Cheque
Después de iniciar la aplicación con el comando, python app.py loginle pedirá un correo y una contraseña. Si estos datos son correctos, el elemento correspondiente aparecerá en el Servicio Secreto.

De hecho, almacena el token.

Cuando reinicie la aplicación, no le pedirá detalles, pero descargará el token del Servicio Secreto.