Недавно я столкнулся с спросом, когда работал над Sparrow (удобная система Mock, которая все еще находится на внутреннем тестировании 😁). Сервер Sparrow — это продукт, написанный с использованием Django 2.0, поэтомуВсе фоны кода в этой статье представляют собой среда Django 2.0 и языком Python 3.6.3, целое является Vue + Django + Sqlite.
Операции Sparrow обычно выполняются на веб-странице, а мобильный клиент часто используется для синхронизации некоторых простых данных. Итак, вот другой опыт и распространенные сценарии использования APP.
Вообще говоря, работа продукта в основном осуществляется на мобильном телефоне, затем клиент для ПК и веб-версия могут сканировать код для входа в систему через уже зарегистрированное мобильное приложение.
Текущая ситуация такова, что Sparrow чаще всего используется в веб-версии, поэтому мне нужно, чтобы пользователи мобильных приложений сохраняли операцию входа в систему, вводя имя пользователя и пароль, когда они уже вошли в веб-версию, и позвольте пользователям мобильного приложения сканировать веб-страницу QR-код для завершения входа в мобильное приложение.
Грубый вариант использования
##Идеи дизайна
Отсканируйте код, чтобы войти по URL-адресу
Прежде всего, сервер должен предоставить URL-адрес, к которому может получить доступ мобильное приложение (показанный двумерный код для сканирования приложения), этот URL-адрес должен
- уникальный идентификатор пользователя
- код верификации
Тогда приблизительный вид его URL:
frontend/account/quick_login?user_id=<user_id>&verification_code=<verification_code>
код верификации
Откуда взялся проверочный код?
Причина в том, что явно неразумно, если URL-адрес для сканирования логина постоянно действителен, а это означает, что, пока URL-адрес получен, любой может войти в учетную запись пользователя в любое время через этот URL-адрес, поэтому проверочный код требуется.
в то же время,Код должен сопровождаться время поколения, чтобы добитьсяКод подтверждения действителен в течение одной минутыОсобенность. Для этого создайте модель с внешним ключом пользователя:
class QuickLoginRecord(models.Model, Dictable):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
create_time = models.DateTimeField(auto_now_add=True)
update_time = models.DateTimeField(auto_now=True)
verification_code = models.CharField(max_length=32, null=True, default='')
Соответствующая база данных, созданная Django:
Когда генерируется код подтверждения, это, конечно, когда генерируется QR-код.Поэтому этот URL-адрес запрашивается не для мобильного терминала, а для внешнего интерфейса.Когда внешний интерфейс входит в систему, доступ к URL-адресу может напрямую передать информацию о пользователе, серверная часть создает запись QuickLoginRecord, получая информацию о пользователе.
Внешний доступ и URL-адрес кода подтверждения:
frontend/account/request_quick_login
Далее весь процесс (опуская подробности):
внутренний код
url.py
urlpatterns = [
// ···
path('frontend/account/quick_login', AccountAction.quick_login),
path('frontend/account/request_quick_login', AccountAction.request_quick_login),
]
models.py
class QuickLoginRecord(models.Model, Dictable):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
create_time = models.DateTimeField(auto_now_add=True)
update_time = models.DateTimeField(auto_now=True)
verification_code = models.CharField(max_length=32, null=True, default='')
account_action.py
Если вы не хотите видеть код здесь, кратко опишите процесс:
def request_quick_login(request: HttpRequest)
- Указывает, что HTTPMethod должен иметь доступ GET.
- Получить параметр user_id в запросе
- Запрос записей QuickLoginRecord по user_id
- Если результата запроса нет, создается новая запись QuickLoginRecord, связанные пользовательские настройки, код_верификации (create_time update_time и автоматически предоставляется в QuickLoginRecordDao)
- Если результат запрошен, обновите поле Verification_Code (update_time автоматически устанавливается в QuickLoginrecorddao)
- Вернуть успех
@track(AccountRequestQuickLogin)
def request_quick_login(request: HttpRequest):
if request.method != CommonData.Method.GET.value:
return HttpResponse(Response.methodInvalidResponse().toJson(), content_type='application/json')
user = request.user
r = QuickLoginRecordDao.get_record_with_user_id(user.id)
if r is not None:
r.verification_code = str(uuid.uuid1())
QuickLoginRecordDao.update_record(r)
response = Response(Success, 'Success', {'verification_code': r.verification_code})
return HttpResponse(response.toJson(), content_type='application/json')
else:
record = QuickLoginRecord()
record.user = user
record.verification_code = str(uuid.uuid1())
QuickLoginRecordDao.add_record(record)
response = Response(Success, 'Success', {'verification_code': record.verification_code})
return HttpResponse(response.toJson(), content_type='application/json')
def quick_login(request: HttpRequest):
- Указывает, что HTTPMethod должен иметь доступ GET.
- Получить user_id в запросе
- Получить код подтверждения в запросе
- Получить QuickLoginRecord с кодом подтверждения
- Если запись не существует, в ней указано, что коды не существуют или срок их действия истек.
- Если он существует, сравните поле Update_Time, чтобы определить, превысило ли он 60 секунд
- Более 60 секунд для возврата «Срок действия кода подтверждения истек»
- Войдите в систему в течение 60 секунд
- Вернуть успех
@track(AccountQuickLogin)
def quick_login(request: HttpRequest):
if request.method != CommonData.Method.GET.value:
return HttpResponse(Response.methodInvalidResponse().toJson(), content_type='application/json')
user_id = request.GET.get('user_id')
verification_code = request.GET.get('verification_code')
record = QuickLoginRecordDao.get_record_with_verification_code(verification_code)
if record is None:
response = Response(QuickLoginFailed, '验证码不存在或已过期', {})
return HttpResponse(response.toJson(), content_type='application/json')
now = datetime.now(timezone.utc)
offset = (now - record.update_time).seconds
if offset > 60:
response = Response(QuickLoginFailed, '验证码已过期', {})
return HttpResponse(response.toJson(), content_type='application/json')
user = AccountDao.get_user_with_id(user_id)
if user is None:
response = Response(QuickLoginFailed, '用户不存在', {})
return HttpResponse(response.toJson(), content_type='application/json')
user.backend = 'django.contrib.auth.backends.ModelBackend'
print('用户 ' + user.username + ' 尝试登录')
auth.login(request, user)
accountInfo = User.objects.get(id=user.id)
response = Response(Success, 'Success', {'id': accountInfo.id,
'username': accountInfo.username,
'email': accountInfo.email})
return HttpResponse(response.toJson(), content_type='application/json')
quick_login_record_dao.py
class QuickLoginRecordDao:
@staticmethod
def add_record(record):
record.save()
@staticmethod
def get_record_with_user_id(user_id):
try:
record = QuickLoginRecord.objects.get(user_id=user_id)
return record
except:
return None
@staticmethod
def update_record(record):
result = QuickLoginRecord.objects.filter(id=record.id).update(
verification_code=record.verification_code,
update_time=datetime.datetime.now())
if result > 0:
return True
else:
return False
@staticmethod
def get_record_with_verification_code(code):
try:
record = QuickLoginRecord.objects.get(verification_code=code)
return record
except:
return None
интерфейсный код
Эффект фронтенда следующий:
В состоянии входа в систему нажмите кнопку «Вход с кодом сканирования клиента» в правом верхнем углу, и появится QR-код.
Для динамических эффектов, модальных окон и т.п. я не буду приводить слишком много кода, а только сосредоточусь на коде основного процесса:
Кнопки панели навигации
<p class="nav-item" v-if="account.status">
<button class="button is-primary" type="submit" @click="openModalImage">客户端扫码登录 </button>
</p>
функция openModalImage
openModalImage () {
const imageModal = openImageModal()
imageModal.loading = true
var baseUrl = window.location.protocol + '//' + window.location.host
request('/frontend/account/request_quick_login', {
method: 'get'
}).then((response) => {
var verificationCode = response.data.verification_code
var url = baseUrl + '/frontend/account/quick_login' + '?' +
'verification_code=' + verificationCode + '&' +
'user_id=' + this.accountInfo.id
QRCode.toDataURL(url)
.then(url => {
imageModal.imgUrl = url
imageModal.loading = false
imageModal.$children[0].active()
})
.catch(err => {
console.error(err)
})
}).catch((response) => {
notification.toast({
message: response.message,
type: 'danger',
duration: 2000
})
})
}
iOS-код
Код iOS не будет отображаться, просто отсканируйте код, чтобы получить доступ к URL-адресу в QR-коде, а затем добавьте некоторые недопустимые суждения об URL-адресах.
Суммировать
Пройдя весь процесс, вы можете почувствовать, что это похоже на оплату скан-кодом Alipay. Предоставьте клиенту регулярно обновляемый QR-код, чтобы он мог отсканировать его для входа в систему.
Конечно, может быть идеальное место, например, предыдущий двумерный код в режиме открытого окна, регулярно обновляется один раз в 60 секунд.