ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

django-allauth 账户适配器(AccountAdapter)完全指南:定制 DefaultAccountAdapter 的钩子方法与实战

django-allauth 账户适配器(AccountAdapter)完全指南:定制 DefaultAccountAdapter 的钩子方法与实战 后端认证鉴权身份认证【免费下载链接】django-allauthIntegrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication. Mirror of https://codeberg.org/allauth/django-allauth/项目地址https://gitcode.com/gh_mirrors/dj/django-allauth点击查看免费下载导读本文聚焦 django-allauth 中allauth.account应用的适配器Adapter扩展点以docs/account/adapter.rst所指向的DefaultAccountAdapter类为骨架结合 adapter.py 源码与仓库测试用例系统讲解如何通过自定义适配器改写邮箱发送、登录/注册流程、重定向、用户校验、验证码生成、重新认证等行为。读完本文你将掌握ACCOUNT_ADAPTER的配置方式、DefaultAccountAdapter全部核心钩子方法的分组与作用并能在自己的 Django 项目中安全、精准地覆盖这些方法实现业务定制。本文对应的官方文档入口为 docs/account/adapter.rst它是该主题的唯一权威来源本文以其为主体展开并补充源码细节。一、什么是 Account Adapter为什么需要它在 django-allauth 中Adapter 是一种策略/钩子hook机制框架把可变的业务决策点集中暴露在一组可继承、可覆盖的方法上让开发者不必 fork 源码就能改动默认行为。DefaultAccountAdapter的类注释adapter.py写得很明确The adapter class allows you to override various functionality of theallauth.accountapp. To do so, pointsettings.ACCOUNT_ADAPTERto your own class that derives fromDefaultAccountAdapterand override the behavior by altering the implementation of the methods according to your own needs.即自定义类必须继承DefaultAccountAdapter只重写你需要改变的方法其余行为保持默认。该类的代码体量约 1000 行覆盖了近 70 个可覆盖方法几乎囊括了普通账户流程中所有可定制点邮件渲染与发送主题前缀、发件人、HTML/纯文本双格式登录/注册/登出后的跳转 URL注册开放策略、用户实例创建、用户名填充与唯一化用户名/邮箱/密码/手机号的校验钩子登录前置/后置处理、认证与登录失败处理消息闪现django.contrib.messages与 AJAX 响应重定向安全校验Open Redirect 防护登录码、密码重置码、邮箱验证码、手机验证码的生成登录阶段Login Stages与重新认证Reauthentication方法列表手机号相关的一整套可插拔接口。工厂函数get_adapter()位于 adapter.py它从配置读取适配器类路径并实例化def get_adapter(request: HttpRequest | None None) - DefaultAccountAdapter: return import_attribute(app_settings.ADAPTER)(request)整个allauth.account内部流程登录、注册、改密、邮箱管理、密码重置等都通过get_adapter()获取适配器实例再调用对应方法因此覆盖这些方法即可从流程内部改变行为。二、如何自定义配置 ACCOUNT_ADAPTER2.1 配置项ACCOUNT_ADAPTER的默认值为字符串allauth.account.adapter.DefaultAccountAdapter在 app_settings.py 中定义property def ADAPTER(self) - str: return self._setting(ADAPTER, allauth.account.adapter.DefaultAccountAdapter)该配置项同时收录在配置文档 docs/account/configuration.rst 的 Overall 一节中。2.2 编写自定义适配器在项目里新建myproject/adapters.pyfrom allauth.account.adapter import DefaultAccountAdapter class MyAccountAdapter(DefaultAccountAdapter): def is_open_for_signup(self, request): # 例如仅允许通过邀请码注册 return True然后在settings.py中指向它ACCOUNT_ADAPTER myproject.adapters.MyAccountAdapter2.3 验证生效仓库测试用例示范仓库自带适配器测试 tests/apps/account/test_adapter.py 演示了最典型的自定义——在登录前置钩子中抛出ImmediateHttpResponse打断流程并重定向class PreLoginRedirectAccountAdapter(DefaultAccountAdapter): def pre_login(self, *args, **kwargs): raise ImmediateHttpResponse(HttpResponseRedirect(/foo)) def test_adapter_pre_login(settings, user, user_password, client): settings.ACCOUNT_ADAPTER ( tests.apps.account.test_adapter.PreLoginRedirectAccountAdapter ) resp client.post( reverse(account_login), {login: user.username, password: user_password}, ) assert resp.status_code HTTPStatus.FOUND assert resp[location] /foo可以看到pre_login返回HttpResponse或抛出ImmediateHttpResponse都能直接中断登录流程这也是is_open_for_signup等钩子文档中提到的通过抛出ImmediateHttpResponse介入常规流程的机制来源。ImmediateHttpResponse定义于 allauth/core/exceptions.py。三、错误消息字典error_messagesDefaultAccountAdapter顶部定义了一整张错误消息映射adapter.py覆盖了账户流程中几乎所有可预见的错误码例如错误码默认文案中文场景可覆盖account_inactiveThis account is currently inactive.email_takenA user is already registered with this email address.username_taken直接复用AbstractUser.username字段的 unique 错误消息too_many_login_attemptsToo many failed login attempts. Try again later.invalid_or_expired_keyInvalid or expired key.unverified_primary_emailYour primary email address must be verified.rate_limitedBe patient, you are sending too many requests.max_email_addressesYou cannot add more than %d email addresses.支持%占位符这些消息通过基类BaseAdapter.validation_error()allauth/core/internal/adapter.py生成 DjangoValidationErrordef validation_error(self, code, *args) - ValidationError: message self.error_messages[code] if args: message message % args exc ValidationError(message, codecode) return exc自定义适配器可以整体替换这张字典实现品牌化或本地化文案。四、邮件相关钩子渲染、主题、发件人与发送邮件是账户流程的核心载体验证邮件、密码重置、安全通知DefaultAccountAdapter提供了从主题到正文、从渲染到发送的完整钩子链。4.1 主题与发件人format_email_subject(subject)adapter.py为邮件主题添加前缀。默认读取ACCOUNT_EMAIL_SUBJECT_PREFIX见 configuration.rst 的 Sending Email 一节若该配置为None则自动使用[当前 Site 名称]作为前缀。get_from_email()adapter.py返回发件人地址默认取 Django 的settings.DEFAULT_FROM_EMAIL。文档注释明确这是一个可以覆盖以便程序化设置发件人的钩子。4.2 渲染与发送管线render_mail(template_prefix, email, context, headersNone)adapter.py是核心渲染方法工作流程如下以{template_prefix}_subject.txt渲染主题合并多余换行并经过format_email_subject加前缀按ACCOUNT_TEMPLATE_EXTENSION默认html与txt两种扩展名依次尝试渲染{template_prefix}_message.{ext}正文若两者都存在则构造EmailMultiAlternativesHTML 正文作为attach_alternative(..., text/html)附件若只有 HTML 则构造EmailMessage并设置content_subtype html若连纯文本都不存在则抛出TemplateDoesNotExist。send_mail(template_prefix, email, context)adapter.py负责把request、email、current_site注入上下文后调用render_mail并真正msg.send()。4.3 场景化发送钩子方法作用send_confirmation_mail(request, emailconfirmation, signup)发送邮箱验证邮件根据ACCOUNT_EMAIL_VERIFICATION_BY_CODE_ENABLED决定邮件携带code验证码模式还是keyactivate_url链接模式注册场景使用account/email/email_confirmation_signup模板否则用account/email/email_confirmationsend_password_reset_mail(user, email, context)发送密码重置邮件。文档注释特别指出若实现仅第三方登录social only等策略可在此通过user.has_usable_password介入判断是否允许重置send_account_already_exists_mail(email)当用户用已存在账号的邮箱再次注册时发送提示邮件上下文中注入signup_url与password_reset_urlsend_notification_mail(template_prefix, user, contextNone, emailNone)仅在ACCOUNT_EMAIL_NOTIFICATIONS True时发送安全通知如密码已修改自动附带时间戳、客户端 IP 与 User-Agent若未显式传email则取用户主邮箱get_email_confirmation_url(request, emailconfirmation)adapter.py构造邮箱确认激活链接委托给allauth.account.internal.flows.email_verification内部流程注释提醒若确认邮件在请求上下文之外发送request可能为None。五、重定向钩子登录、注册、登出与验证后去向这些方法统一返回可被resolve_url解析的 URL 或 URL nameget_login_redirect_url(request)adapter.py登录后默认跳转读取settings.LOGIN_REDIRECT_URL。注意显式传入的next参数优先级更高同时兼容已废弃的LOGIN_REDIRECT_URLNAME会触发DeprecationWarning。get_signup_redirect_url(request)adapter.py注册成功后的跳转默认ACCOUNT_SIGNUP_REDIRECT_URL即settings.LOGIN_REDIRECT_URL。get_logout_redirect_url(request)adapter.py登出后跳转默认ACCOUNT_LOGOUT_REDIRECT_URL回退到 Django 的LOGOUT_REDIRECT_URL或/。注释提醒该方法在未登录就请求登出时也会被调用因此不要假设request.user一定已认证。get_email_verification_redirect_url(email_address)adapter.py邮箱验证完成后的去向。已登录用户优先使用ACCOUNT_EMAIL_CONFIRMATION_AUTHENTICATED_REDIRECT_URL否则回落到登录跳转匿名用户使用ACCOUNT_EMAIL_CONFIRMATION_ANONYMOUS_REDIRECT_URL默认settings.LOGIN_URL。内部还兼容已废弃的get_email_confirmation_redirect_url。get_password_change_redirect_url(request)adapter.py改密/设密成功后跳转默认account_change_password。注释特别说明密码重置流程不会调用本方法。这些方法对应的配置项均可在 docs/account/configuration.rst 的 Routing 一节找到完整默认值与说明。六、注册流程钩子开放策略、用户创建与字段校验6.1 流程级钩子is_open_for_signup(request)adapter.py是否开放注册。除了返回True/False还可以通过抛出ImmediateHttpResponse介入常规流程例如重定向到邀请页。new_user(request)adapter.py实例化新用户默认get_user_model()()可覆盖以注入默认值。save_user(request, user, form, commitTrue)adapter.py用注册表单数据填充用户——写入 email、username、first_name、last_name从password1/password字段设置密码无密码则set_unusable_password()随后调用populate_username补齐用户名最后commit时保存若表单带手机字段form._has_phone_field还会调用set_phone(user, phone, False)。populate_username(request, user)adapter.py当ACCOUNT_USER_MODEL_USERNAME_FIELD存在且用户名为空时基于 first_name / last_name / email 等候选文本调用generate_unique_username自动生成。generate_unique_username(txts, regexNone)adapter.py委托给allauth.utils.generate_unique_username生成不冲突的用户名。6.2 字段级校验钩子方法默认行为典型覆盖场景clean_username(username, shallowFalse)依次执行ACCOUNT_USERNAME_VALIDATORS校验器、ACCOUNT_USERNAME_BLACKLIST黑名单检查shallowFalse时还会查询数据库保证唯一username_taken动态限制可用用户名如禁止包含敏感词clean_email(email)原样返回动态限制可选邮箱域名clean_password(password, userNone)若ACCOUNT_PASSWORD_MIN_LENGTH有值则用 DjangoMinimumLengthValidator校验再调用validate_password(password, user)执行项目全部密码校验器附加业务密码规则clean_phone(phone)原样返回校验手机号格式/归属地validate_unique_email(email)原样返回在表单层之外自定义邮箱唯一性逻辑相关配置ACCOUNT_USERNAME_BLACKLIST、ACCOUNT_USERNAME_VALIDATORS、ACCOUNT_PASSWORD_MIN_LENGTH等的完整说明见 docs/account/configuration.rst 的 Signup 与 User Model 两节。七、登录认证钩子前置、后置、认证与限流7.1 登录前后钩子pre_login(request, user, *, email_verification, signal_kwargs, email, signup, redirect_url)adapter.py登录流程早期钩子。默认实现仅检查user.is_active不活跃则调用respond_user_inactive返回账号未激活响应。可覆盖以插入自己的拦截逻辑见上文测试示例。post_login(...)adapter.py登录成功后的处理。在 headless无头/API请求下返回AuthenticationResponse否则按get_login_redirect_url重定向随后发送user_logged_in信号并闪现已登录消息。该方法的返回值会被当作视图响应返回可整体替换登录完成页。login(request, user)/logout(request)adapter.py薄封装django.contrib.auth.login/logout。login内部会为缺少backend属性的用户自动挑选可用认证后端优先AuthenticationBackend并回填user.backend。pre_authenticate(request, **credentials)/authenticate(request, **credentials)adapter.py认证前的限流消费与真正的认证调用。authenticate成功后会对失败的限流计数做回滚_rollback_login_failed_rl_usage源码注释解释了原因完全清空限流会让攻击者在爆破过程中穿插成功登录来规避 IP/key 限流。7.2 登录失败限流_get_login_attempts_cache_keyadapter.py以{site.domain}:{login}login 取 email 或 username 的小写形式为缓存键pre_authenticate通过ratelimit.consume消费login_failed配额不足时抛出too_many_login_attempts错误。默认限流策略10/m/ip,{ACCOUNT_LOGIN_ATTEMPTS_LIMIT}/{ACCOUNT_LOGIN_ATTEMPTS_TIMEOUT}s/key在 app_settings.py 中组装完整策略表见 docs/account/rate_limits.rst。7.3 重新认证Reauthenticationreauthenticate(user, password)adapter.py用用户名、主邮箱以及启用手机登录时的已验证手机号拼装凭据再次调用authenticate要求重新认证通过且pk与当前用户一致。get_reauthentication_methods(user)adapter.py返回当前可用的重新认证方式列表按顺序排列第一个为reauthentication_required装饰器默认方式。会依据allauth.account.internal.flows.reauthentication计算出的流程组合使用密码account_reauthenticate、验证器应用或代码mfa_reauthenticate与安全密钥mfa_reauthenticate_webauthn等条目。相关配置ACCOUNT_REAUTHENTICATION_TIMEOUT默认 300 秒内免重复认证与ACCOUNT_REAUTHENTICATION_REQUIRED见 configuration.rst 的 Reauthentication 一节。八、安全相关钩子重定向校验与客户端信息is_safe_url(url)adapter.pyOpen Redirect 防护核心。它将request.get_host()、settings.ALLOWED_HOSTS、settings.CSRF_TRUSTED_ORIGINS解析出的主机合并为允许集合还兼容ALLOWED_HOSTS的通配符/点前缀子域名写法最终委托 Django 的url_has_allowed_host_and_scheme判定。所有next参数都会经过它校验。get_client_ip(request)adapter.py解析客户端 IP无法确定时抛出PermissionDenied(Unable to determine client IP address)。测试 tests/apps/account/test_adapter.py 对X-Forwarded-For的 IPv4/IPv6、端口、方括号、压缩写法做了大量参数化验证并对畸形输入含 SQL 注入样式的XwDxNk4JQhUft)) OR 18(SELECT 18 FROM PG_SLEEP(15))--断言抛出PermissionDenied。get_http_user_agent(request)adapter.py返回HTTP_USER_AGENT缺失时为Unspecifiedsend_notification_mail会按HTTP_USER_AGENT_MAX_LENGTH截断后随通知邮件发送。is_ajax(request)adapter.py兼容三种 AJAX 判定——X-Requested-With: XMLHttpRequest头、application/json内容类型或Accept: application/json。九、消息与 AJAX 响应钩子add_message(request, level, message_templateNone, message_contextNone, extra_tags, messageNone)adapter.pydjango.contrib.messages的封装消息文本从模板渲染而来render_to_string后经html.unescape反转义。headless 请求直接返回不添加消息未安装 messages 框架或模板缺失时静默跳过。ajax_response(request, response, redirect_toNone, formNone, dataNone)adapter.py将视图响应转换为 JSON 结构location重定向目标、formajax_response_form序列化的表单规格、html渲染后的页面片段、data任意附加数据HTTP 状态码随场景切换为 200/400。ajax_response_form(form)adapter.py把 Django 表单序列化为{fields: {...}, field_order: [...], errors: [...]}结构每个字段含label、value、help_text、errors与widget.attrs便于前端如 headless 模式动态渲染。十、验证码生成与登录阶段钩子10.1 验证码生成方法用途底层generate_emailconfirmation_key(email)邮箱确认链接密钥get_random_string(64).lower()generate_login_code()登录码Magic Codegenerate_user_code(**ACCOUNT_LOGIN_BY_CODE_FORMAT)generate_password_reset_code()密码重置码generate_user_code(**ACCOUNT_PASSWORD_RESET_BY_CODE_FORMAT)generate_email_verification_code()邮箱验证码generate_user_code(**ACCOUNT_EMAIL_VERIFICATION_BY_CODE_FORMAT)generate_phone_verification_code(*, user, phone)手机验证码generate_user_code(**ACCOUNT_PHONE_VERIFICATION_CODE_FORMAT)这些方法对应ACCOUNT_*_BY_CODE_FORMAT配置默认继承ALLAUTH_USER_CODE_FORMAT控制验证码的长度与字符集相关配置见 configuration.rst 的 Login、Password Reset、Email Verification 各节。generate_phone_verification_code还保留了无参旧签名的兼容探测逻辑_generate_phone_verification_code_compat会发出DeprecationWarning。10.2 登录阶段Login Stagesget_login_stages()adapter.py返回登录需要依次通过的阶段列表默认顺序为LoginByCodeStage→PhoneVerificationStage→EmailVerificationStage当 MFA 启用时追加AuthenticateStage并视ACCOUNT_MFA_TRUST_STAGE_ENABLED、PASSKEY_SIGNUP_ENABLED追加TrustStage与PasskeySignupStage。开发者可通过覆盖本方法调整登录多步流程的编排。10.3 登录码强制策略is_login_by_code_required(login)adapter.py实现ACCOUNT_LOGIN_BY_CODE_REQUIRED布尔True要求所有用户都必须输入邮件登录码也可传认证方式集合password、mfa、socialaccount仅对这些方式强制。若当前认证方式本身已是code则直接放行避免死循环。十一、手机号Phone可插拔接口手机验证是一组必须由开发者实现的接口默认全部抛出NotImplementedErrorDefaultAccountAdapter通过_has_phone_impl属性adapter.py检查以下 5 个方法是否被覆盖全部覆盖才认为手机功能已完整实现方法签名职责set_phone(user, phone, verified)保存手机号及其验证状态get_phone(user)返回(phone, verified)元组或Noneset_phone_verified(user, phone)将手机号标记为已验证get_user_by_phone(phone)按手机号反查用户无则返回Nonesend_verification_code_sms(user, phone, code, **kwargs)发送验证码短信另外两个可选钩子send_unknown_account_sms(phone)防枚举开启时对未登记手机号也发送一条说明无账号的短信与send_account_already_exists_sms(phone)。phone_form_field(**kwargs)adapter.py返回手机号表单字段allauth.account.fields.PhoneField。仓库测试项目给出了完整可参考的实现样例tests/projects/common/adapters.py 中的AccountAdapter用phone_stub存根实现了上述全部方法包括send_unknown_account_sms与send_account_already_exists_sms并额外覆盖了add_message把消息捕获进messagesoutbox以便断言与clean_email对invalidtest.email抛ValidationError。手机号相关配置ACCOUNT_PHONE_VERIFICATION_*系列见 docs/account/phone.rst。十二、邮箱管理相关钩子stash_verified_email(request, email)/unstash_verified_email(request)/is_email_verified(request, email)adapter.py借助 session 键account_verified_email在注册流程中暂存已在 allauth 之外验证过的邮箱例如用户此前已通过邀请链接验证供注册/邮箱管理流程消费。can_delete_email(email_address)adapter.py判断某邮箱是否可删除。逻辑要点主邮箱primary在存在其他邮箱时禁止直接删除须先改主若登录方式仅限邮箱ACCOUNT_LOGIN_METHODS {email}删除最后一个邮箱会导致账号悬空同样禁止。confirm_email(request, email_address)adapter.py在数据库中将邮箱标记为已确认委托allauth.account.internal.flows.email_verification.verify_email。should_send_confirmation_mail(request, email_address, signup)adapter.py默认True返回False可阻止发送确认邮件如配合外部验证通道。邮箱上限校验max_email_addresses、ACCOUNT_MAX_EMAIL_ADDRESSES等配置见 configuration.rst 的 Email Addresses 一节。十三、基类与工厂函数BaseAdapter 与 get_adapterDefaultAccountAdapter继承自allauth.core.internal.adapter.BaseAdapterallauth/core/internal/adapter.pyclass BaseAdapter: error_messages: dict def __init__(self, request: HttpRequest | None None) - None: # Explicitly passing request is deprecated, just use: # allauth.core.context.request. self.request context.request def validation_error(self, code, *args) - ValidationError: ...要点构造函数会忽略显式传入的request统一从allauth.core.context.request读取当前请求显式传参已废弃validation_error是各钩子抛出标准错误消息的统一入口。get_adapter()工厂负责按ACCOUNT_ADAPTER配置实例化adapter.py。get_adapter()在allauth.account内部被广泛调用如 views.py、stages.py、utils.py、mixins.py 及各内部流程目录 allauth/account/internal/flows因此自定义适配器的方法会被注册、登录、邮箱、密码、手机验证等全部流程自动拾取。十四、快速对照最常用的覆盖场景需求覆盖方法相关配置自定义邮件主题/发件人format_email_subject/get_from_emailACCOUNT_EMAIL_SUBJECT_PREFIX、DEFAULT_FROM_EMAIL登录后去往不同页面get_login_redirect_urlLOGIN_REDIRECT_URL关闭/开放注册is_open_for_signup—限制用户名黑名单clean_usernameACCOUNT_USERNAME_BLACKLIST阻断特定邮箱注册clean_email—登录前强制二次确认pre_login返回响应或抛ImmediateHttpResponse—登录码强制启用is_login_by_code_requiredACCOUNT_LOGIN_BY_CODE_REQUIRED自定义登录/重置/验证码格式generate_*_codeACCOUNT_*_BY_CODE_FORMAT接入短信服务set_phone/get_phone/set_phone_verified/get_user_by_phone/send_verification_code_smsACCOUNT_PHONE_VERIFICATION_*拒绝不安全重定向is_safe_url默认已启用ALLOWED_HOSTS、CSRF_TRUSTED_ORIGINS总结DefaultAccountAdapter是 django-allauth 普通账户allauth.account流程的总控制面板从邮件发送、跳转路由、注册与校验、登录认证与限流到验证码生成、登录阶段编排、重新认证与手机验证几乎所有业务决策点都以可覆盖方法的形式暴露。正确姿势是继承它、按需覆写、保持其余默认并通过ACCOUNT_ADAPTER指向自定义类。覆盖方法时建议同步阅读 adapter.py 对应方法源码、参考 tests/apps/account/test_adapter.py 与 tests/projects/common/adapters.py 的现成范例并结合 docs/account/configuration.rst 中相关配置项的默认值即可实现既安全又灵活的账户行为定制。赞分享后端认证鉴权身份认证【免费下载链接】django-allauthIntegrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication. Mirror of https://codeberg.org/allauth/django-allauth/项目地址https://gitcode.com/gh_mirrors/dj/django-allauth点击查看免费下载相关推荐django-allauth 社交登录高级用法Adapter 钩子、Provider 定制与 Scope 扩展实战指南django allauth 社交登录高级用法Adapter 钩子、Provider 定制与 Scope 扩展实战指南 导读 本指南面向已经跑通 django后端认证鉴权身份认证django-allauth 社交登录适配器DefaultSocialAccountAdapter完整指南从配置到方法级定制django allauth 社交登录适配器DefaultSocialAccountAdapter完整指南从配置到方法级定制 导读 本文聚焦 django后端认证鉴权身份认证django-allauth 社交登录模板标签完全指南provider_login_url 与社交账户渲染实战django allauth 社交登录模板标签完全指南provider_login_url 与社交账户渲染实战 本文面向在 Django 项目中集成第三方社后端认证鉴权身份认证上一篇ManiSkill 控制类任务Control Tasks全解析面向 GPU 并行仿真的 9 个经典连续控制基准下一篇Airweave 检索 AgentRetrieval Agent任务规范解析基于向量库的迭代式搜索循环与工具协议创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表