- Add created_at, last_login, login_fail_count, last_login_fail fields - 3 failed logins locks account for 5 minutes - LRU+TTL cache for UserPermissions, thread-safe - All login methods update last_login - Migration SQL for existing databases
23 lines
1.0 KiB
Plaintext
23 lines
1.0 KiB
Plaintext
username = params_kw.get('username')
|
|
passwd = params_kw.get('passwd')
|
|
if not passwd:
|
|
return UiError(title='Login failed', message='Password is required')
|
|
passwd = password_encode(passwd)
|
|
rzt = await check_user_password(request, username, passwd)
|
|
if rzt:
|
|
return UiMessage(title='Logined', message='Welcome back')
|
|
|
|
# Check if account is locked for better error message
|
|
db = DBPools()
|
|
dbname = get_module_dbname('rbac')
|
|
async with db.sqlorContext(dbname) as sor:
|
|
r = await sor.sqlExe('select login_fail_count, last_login_fail from users where username=${username}$', {'username': username})
|
|
if r:
|
|
fail_count = getattr(r[0], 'login_fail_count', 0) or 0
|
|
if fail_count >= 3:
|
|
return UiError(title='Account Locked', message='Account locked due to too many failed login attempts. Please try again in 5 minutes.')
|
|
remaining = 3 - fail_count
|
|
return UiError(title='Login failed', message=f'User and password mismatch ({remaining} attempts remaining)')
|
|
|
|
return UiError(title='Login failed', message='User and password mismatch')
|