Discourse 集成 Django 登录

最近搭建了一个 Discourse 论坛,尝试使用另一个已有的 Django 系统中的账号进行登录。踩了一些小坑,下面记录一下过程。

本文内容基于以下软件以及版本:

  • Discourse 3.1.0.beta5
  • Django 4.2.2
  • Django Oauth Toolkit 2.3.0

安装 Discourse

Discourse 的安装比较顺利,基本上按官方说明操作即可。最好使用一台没有 Web 服务的机器,即 80 和 443 端口没有被占用,否则会有一些麻烦。

域名我是通过 Cloudflare 管理的,一开始一直遇到“ERR_TOO_MANY_REDIRECTS”错误,查询之后发现是因为“SSL/TLS 加密模式”需要使用“完全”模式,不能使用默认的“灵活”模式。

邮件发送服务,先是试了下阿里云的邮件推送,后来又根据 Discourse 安装说明页面的推荐,选了 Mailjet 的服务。阿里云邮件推送和 Mailjet 都可以支持,且两者每天都有 200 封免费额度,对小应用来说足够了。

Discourse 准备

Discourse 内置了 Google、Facebook、GitHub、Twitter 等第三方登录,只需在设置中配置开启即可。不过如果想集成自定义 OAuth2 登录服务,还需要安装一个由官方维护的额外插件 discourse-oauth2-basic

插件安装方式为修改 Discourse 服务器上 /var/discourse/containers 目录下的 app.yml 文件,找到其中 hooks 字段,将插件的 git 仓库地址添加到 cmd 中,如下面的代码所示:

hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/discourse/discourse-oauth2-basic.git

注意其中的 docker_manager.git 是默认有的,最后一行的 discourse-oauth2-basic.git 则是新添加的。

添加完成之后,在 /var/discourse 目录下执行以下命令:

./launcher rebuild app

命令的执行过程需要几分钟,完成之后新的配置就生效了。

Django 准备

Django 默认不支持 OAuth2 登录,不过有一个成熟的第三方插件 Django OAuth Toolkit 解决了这个问题,根据官方文档安装即可。

安装完成并在 settings.py 中引入 Django OAuth Toolkit 之后,记得添加下面一项配置:

OAUTH2_PROVIDER = {
  # 其他配置项...
  'PKCE_REQUIRED': False,
}

Django OAuth Toolkit 默认启用 PCKE,但目前 Discourse 的 OAuth2 插件还不支持 PKCE,如果不把 Django 中的 PKCE_REQUIRED 设为 False,后面登录时可能会遇到 invalid_request 错误,具体错误描述为“Code challenge required.”。

另外,也需要为 Django OAuth Toolkit 服务指定一个访问地址,比如在站点的 url.py 中添加类似下面的记录:

path('oauth/', include('oauth2_provider.urls', namespace='oauth2_provider')),

之后便可以通过 https://YOUR_DJANGO_SITE/oauth/* 访问 OAuth2 接口。

最后,还需要在 Django 站点中准备一个页面,可以使用 OAuth2 授权访问,页面内容为以 JSON 格式显示的用户信息,以便 Discouse 登录成功后读取用户名、Email 等信息。

Django 配置

在 Django 管理后台的“Django OAuth Toolkit” → “Application”中新添加一条记录。各项填写要点如下:

  • Client id:使用默认值或你指定的值
  • User:留空
  • Redirect uris:填写形如 https://YOUR_DISCOURSE_SITE/auth/oauth2_basic/callback 的值,你需要把中间的 YOUR_DISCOURSE_SITE 替换为你的 Discourse 站点的域名
  • Client type:选择“Confidential”
  • Authorization grant type:选择“Authorization code”
  • Client secret:使用默认值或你指定的值,注意如果你决定使用默认值,需要在第一次添加记录时将值复制出来,因为后面再打开这条记录时将只能看到哈希后的值
  • Name:取一个容易记忆或识别的名字即可,比如“Discourse”
  • Skip authorization:此项用于控制在登录成功之后,要不要给用户显示一个是否授权登录的确认页面。建议勾选,因为那个页面默认样式很简陋,影响体验

其余没有提到的项使用默认值即可。

Discourse 配置

最后,再回到 Discourse 这边的配置。

在 Discourse 的插件管理页面,可以看到安装的插件列表,点击 discourse-oauth2-basic 插件的设置按钮可进入对应的设置页面。

当然,你也可以在总设置的“登录”面板下看到相关的设置,不过那个面板选项很多,如果只想设置 OAuth2 相关的选项,可以点击插件的设置按钮以过滤掉无关项。

以下是主要设置项以及说明。

  • oauth2 enabled:选中此项以启用 OAuth2 登录
  • oauth2 client id:即 Django 后台设置的 Client id
  • oauth2 client secret:即 Django 后台设置的 Client secret
  • oauth2 authorize url:Django 后台的 OAuth2 授权地址
  • oauth2 token url:Django 后台获取 Token 的地址

其中 oauth2 authorize urloauth2 token url 和你的 Django 配置有关,如果你配置的 OAuth2 服务的前缀为 /oauth/ ,则对应的地址如下:

# oauth2 authorize url
https://YOUR_DJANGO_SITE/oauth/authorize/

# oauth2 token url
https://YOUR_DJANGO_SITE/oauth/token/

之后的 oauth2 token url method 选择 POST,再之后的 oauth2 callback user id pathoauth2 callback user info paths 留空或使用默认值即可。

再下面则是 oauth2 fetch user details 相关的字段,你需要先在 Django 站点准备好一个页面,比如页面为 https://YOUR_DJANGO_SITE/api/account/info,返回内容形如:

{
  "data": {
    "uid": "xxx",
    "username": "my_name",
    "email": "me@myemail.com"
    // ......
  }
}

还可以添加更多字段,比如用户全名、头像图片地址、Email 是否已验证等等。

随后,将相关字段填写到接下来的字段中即可。比如:

  • oauth2 user json url:填写 https://YOUR_DJANGO_SITE/api/account/info
  • oauth2 json user id path:填写 data.uid
  • oauth2 json user name path:填写 data.username
  • oauth2 json email path:填写 data.email

其余字段根据需要填写即可。

如果一切顺利,你的 Discourse 站点就可以使用 Django 站点的账号登录了。

分类:编程标签:Django

相关文章:

评论:

暂无评论

发表评论: