# `accounts` Accounts & Authentication Author: Zhenyu Yang Last updated: Apr 24, 2026 Corresponding API docs: [Authentication & User Account API](../../api/accounts.md) ## `accounts` Code Entry - `backend/apps/accounts/models/__init__.py` - `backend/apps/accounts/views/__init__.py` - `backend/apps/accounts/serializers/__init__.py` - `backend/apps/accounts/authentication.py` - `backend/apps/accounts/middleware.py` ## `accounts` Core Data ### `User` - Inherits from `AbstractUser`. - Business fields include: - `user_code` - `full_name` - `wxid` - `roles` - `status` - `student_class` - `totp_secret` - `is_totp_enabled` - `preferred_locale` - `auth_version` - `roles` stores all roles assigned to the user. - `current_role` is not stored in the database; it is extracted at runtime from the JWT or request headers. - `auth_version` is used for token revocation; it increments on password, role, or status changes, automatically invalidating old tokens. ### WebAuthn Tables - `WebAuthnCredential`: Stores registered security keys. - `WebAuthnChallenge`: Stores registration/login challenge values. ## Authentication Flows ### Email / Student ID / Staff ID Login - Entry: `EmailLoginView` - The identifier field accepts both email and `user_code`. - Passwords are first attempted to be decrypted via SM2; on failure, the fallback allows plaintext for compatibility. - If the user has TOTP enabled, a `totp_code` must also be submitted during login. ### WeChat Mini Program Login - Entry: `WeChatLoginView` - Calls WeChat `code2session` and locates the user by `wxid=open_id`. - The mini program does not use cookies; it returns access/refresh tokens in the response body. - If the account has TOTP enabled, a `totp_code` is also required. ### WebAuthn Login - Login options: `WebAuthnLoginOptionsView` - Login verification: `WebAuthnLoginView` - After successful login, same as email login: returns tokens and writes HttpOnly cookies. ### TOTP - `setup` generates a secret key and `provisioning_uri`. - `enable` verifies the code and activates TOTP. - `disable` requires verifying the code again when TOTP is already enabled. ## `accounts` Permission Boundaries - User list, user detail, user create/update/delete: - `superadmin` or `secretary` only. - Invite foreign teacher: - `superadmin` or `secretary` only. - Update roles: - `superadmin` only. - Update account status: - `superadmin` or `secretary`. - `/auth/me`: - All authenticated users can read and update their own language preference. ## User Import - Entry: `UserViewSet.import_users` - `superadmin` / `secretary` only. - Uses `user_code` as the unique key. - Existing records are skipped without being overwritten. - Newly created users uniformly receive: - `status="active"` - `set_unusable_password()` - The Excel file only accepts basic identity fields; plaintext or hashed passwords are never written from the import file. ## Implementation Highlights - `CookieJWTAuthentication` reads the Authorization header first, then falls back to the cookie. - `CurrentRoleMiddleware` validates that the `current_role` in the request belongs to `user.roles`; if invalid, it falls back to the default role. - On login or first access, if the user has no valid `preferred_locale`, the system auto-normalizes the `Accept-Language` header to `zh-CN` or `en-US`. - The foreign teacher email registration endpoint `EmailRegisterView` is an anonymous endpoint; the user is logged in immediately after creation. - `SM2PublicKeyView` distributes the public key to the frontend via `/api/v1/accounts/sm2/public-key`.