я не уверен, в чем может быть проблема. Он отлично работает на компьютерах и различных устройствах iOS, где мы его тестировали. У меня Samsung S23 с Android 14 и последней доступной версией Chrome. Он также был протестирован на POCO и дал тот же отрицательный результат.
Я использую WebAuthn 2.2.0, и вот как у меня есть конечные точки:Регистрация:
Принять вызов:
Код: Выделить всё
def get_challenge_authn(request):
try:
rp_id = "localhost"
registration_options = generate_registration_options(
rp_id = rp_id,
rp_name = "MySite",
user_name = user.username,
user_display_name=user.username
)
if not registration_options:
return JsonResponse({'status': 'error', 'msg': 'Ocurrio un error. Contacte a soporte'}, status=500)
# Almacena temporalmente el challenge en la sesión del usuario.
request.session['webauthn_challenge'] = base64.urlsafe_b64encode(registration_options.challenge).decode("utf-8").rstrip("=")
return JsonResponse(options_to_json(registration_options), safe=False)
except Exception as e:
return JsonResponse({'status': 'error', 'msg': e}, status=500)
Код: Выделить всё
def verificar_guardar_registro_authn(request):
body = json.loads(request.body)
try:
credential_data = {
"rawId": body['rawId'],
"response": {
"clientDataJSON": body['response']['clientDataJSON'],
"attestationObject": body['response']['attestationObject'],
},
"type": body["type"],
"id": body["id"],
}
stored_challenge = request.session.get('webauthn_challenge')
if not stored_challenge:
return JsonResponse({'status': 'error', 'msg': 'El challenge no se encuentra.'}, status=500)
expected_rp_id = "localhost"
expected_origin = "http://localhost:8000"
verification = verify_registration_response(
credential = credential_data,
expected_challenge = base64url_to_bytes(stored_challenge),
expected_rp_id = expected_rp_id,
expected_origin = expected_origin,
require_user_verification = True
)
if verification.user_verified:
credential = webAuthnCredential.objects.create(
usuario = request.user,
credential_id = base64.urlsafe_b64encode(verification.credential_id).decode("utf-8").rstrip("="),
public_key = base64.urlsafe_b64encode(verification.credential_public_key).decode("utf-8").rstrip("="),
sign_count = verification.sign_count
)
return JsonResponse({'status': 'ok'}, status=201)
else:
return JsonResponse({'status': 'error', 'msg': 'Registro invalido'}, status=400)
except Exception as e:
print(traceback.format_exc())
return JsonResponse({'status': 'error', 'msg': e}, status=500)
И вот как я использую эти услуги: Я использую библиотеку SimpleWebAuthn
Код: Выделить всё
const registrar_autentificacion = async () => {
try {
const url = "{% url 'autentificacion:get_challenge_authn' %}";
const response = await fetch(url);
const options = await response.json();
const attResponse = await SimpleWebAuthnBrowser.startRegistration(JSON.parse(options));
const url_verificacion = "{% url 'autentificacion:verificar_guardar_registro_authn' %}";
const verificationResponse = await fetch(url_verificacion, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': '{{csrf_token}}'
},
body: JSON.stringify(attResponse)
});
if (verificationResponse.ok) {
$('#modal_aviso_upload').modal('show');
console.log('Registro exitoso.');
} else {
mensaje_error.innerText = "Ocurrio un error durante la verificación de la llave."
mensaje_error.style.display = ''
console.log('Error en la verificación.');
}
} catch (err) {
mensaje_error.innerText = `Ocurrio un error durante la verificación de la llave.\nError: ${err}`;
mensaje_error.style.display = ''
console.error('Error en el registro:', err);
}
}
Получить вызов:
Код: Выделить всё
def get_challenge_authn_authentication(request):
try:
rp_id = "localhost"
authentication_options = generate_authentication_options(
rp_id=rp_id,
user_verification=UserVerificationRequirement.REQUIRED
)
request.session['webauthn_challenge'] = base64.urlsafe_b64encode(authentication_options.challenge).decode("utf-8").rstrip("=")
return JsonResponse(options_to_json(authentication_options), safe=False)
except Exception as e:
print(e)
return JsonResponse({'error': 'Error', 'msg': e}, safe=False, status=400)
Код: Выделить всё
def verificar_guardar_autenticacion(request):
auth_data = json.loads(request.body)
stored_challenge = request.session.get('webauthn_challenge')
if not stored_challenge:
return JsonResponse({"error": "Challenge no encontrado en sesión"}, status=500)
credential_id = auth_data['id']
credential = webAuthnCredential.objects.filter(credential_id=credential_id).first()
if not credential:
return JsonResponse({"error": "No se a encontrado la credencial de llave"}, status=404)
expected_rp_id = "localhost"
expected_origin = "http://localhost:8000"
try:
verification = verify_authentication_response(
credential = auth_data,
expected_rp_id = expected_rp_id,
expected_origin = expected_origin,
expected_challenge = base64url_to_bytes(stored_challenge),
credential_public_key = base64url_to_bytes(credential.public_key),
credential_current_sign_count = credential.sign_count
)
if verification.new_sign_count > credential.sign_count:
credential.sign_count = verification.new_sign_count
credential.save()
# Login here
return JsonResponse({"status": "Autenticación exitosa", 'autenticado': True})
except Exception as e:
print(traceback.format_exc())
return JsonResponse({"error": "Fallo en la autenticación", "msg": str(e)}, status=400)
Код: Выделить всё
btn_login?.addEventListener('click', async (e) => {
e.preventDefault();
try {
const url = "{% url 'autentificacion:get_challenge_authn_authentication' %}"
const response = await fetch(url);
const options = await response.json();
const assertionResponse = await SimpleWebAuthnBrowser.startAuthentication(JSON.parse(options));
const url_verificacion = "{% url 'autentificacion:verificar_guardar_autenticacion' %}";
const verificationResponse = await fetch(url_verificacion, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': '{{csrf_token}}'
},
body: JSON.stringify(assertionResponse)
});
const result = await verificationResponse.json();
const { autenticado = false, error = '', msg = '' } = result;
if (autenticado) {
window.location.href = "/";
} else {
mensaje_error.innerText = `Ocurrio un error durante el inicio de sesión.\n${error}: ${msg}`;
mensaje_error.style.display = ''
console.log('Error en la verificación.');
}
} catch (error) {
mensaje_error.innerText = `Ocurrio un error durante el inicio de sesión.\nError: ${error}`;
mensaje_error.style.display = ''
console.error('Error en la autenticación:', error);
}
});
[img]https:// i.sstatic.net/pBw43wjf.jpg[/img]
После того, как я изменил предпочитаемый сервис (первоначально у меня был Samsung Pass, а теперь я установил его на Google), я получаю сообщение, что зарегистрированных ключей нет (прописал ключ после смены сервиса).
Подробнее здесь: https://stackoverflow.com/questions/791 ... op-and-ios