Discordの一部住民だけに利用してほしいサービスを作りたいという人向け。
ロールを取得するにはbotアカウントが必要なので、botの招待は必要になるが、別に管理人権限などなくても出来る。
もともとはeveryoneのロールIDも調べればサーバーの住民ってことを認証できると思ってたけど、どうやらeveryoneのロールIDはないっぽい。残念。
0.Discordの開発者アカウントをつくり、OAuth2認証用のClientIDや、botトークンを取得する
Discord Developer PortalでNew Applicationでアプリ新規作成を行う。OAuth2/Generalの項目で、Client IDとClient Secretを取得する。Redirects設定はあとでいい。
また、botが必要になるので同じアプリ内でbotを作成し、botのトークンを取得する。botの設定は使い方によるだろうが、public bot/server members intent/message content intentの三つだけ自分はオンにした。その状態でOAuth2/URL Generatorの方にいき、botにチェックをいれて、パーミッションを設定するとアドレスが下部にでる。そのアドレスに跳ぶと、botをサーバーに招待できる。
ここらへんの細かい説明は他のサイトにも調べればかなりあるので、まぁたぶん大丈夫だろう(Permission設定とかややこしいけれど)。
1.omniauth、omniauth-discordをインストールする
railsの認証といえばdeviseというgemを使うのが普通だが、DiscordなどのOAuth2認証でアカウントをつくるだけならばDeviseは必要ない。Omniauthは配布されているストラテジーをインストールすれば、対応しているサイトのOAuth認証を手軽に実装することができる。
omniauthとomniauth-discordの実装は後で細かく書くが、基本的にはomniauth(twitter/facebook/github)実装まとめをそのままやれば問題無くできる。
2.Discordrbをインストールする
railsでDiscordのbot関係を弄るのに必要なgemはdiscordrbなのでこちらをインストール。
なお、このgemはlibsodiumというライブラリを使うらしく、自分は開発段階でも本番段階でもこいつにかなーり振り回された。検索しても、これによって苦労したという人がかなり多数いる。音関係に必要らしいが、いらないのなら無視できるようにしたらいいんだけど。herokuではhttps://github.com/xrisk/heroku-opus
、https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest
、https://github.com/challengee/heroku-buildpack-libsodium
の三つをBuildpacksに入れることで動くようになったので参考にしてね。
昔は強制インストールっぽいと思ってたけど、音関係の機能を使わないなら別に放置でいいらしい。ログで「lisbodiumないけどええんか?」って再三いわれて鬱陶しいけどね。
3.DiscordrbのAPIクラスを利用する
想定では、userモデルでサインアップしたユーザーのデータを取得するので、app/models/user.rb
を弄る。
def self.find_or_create_from_auth(auth)
provider = auth[:provider]
uid = auth['uid']
duser = Discordrb::API::Server.resolve_member("Bot " + ENV['DISCORD_BOT_TOKEN'] ,ENV['DISCORD_SERVERID'],uid)
Discordrb::APIクラスで、botのAPIを使ったデータの取得が可能なので、ロール情報を含んだユーザーデータがとれる。
roleIDは持っているものそれぞれ調べられるので、たとえば運営権限の人間にだけなど制限ができる。
ユーザー情報にたとえばauthorityみたいなカラムを持たせて、スタッフ相当なら30、管理者は50…みたいな値をもたせれば、あとあとif @user.authority > 29
みたいな簡単な条件文でページ別のアクセス制限も実装できる。
ちなみに、一応直接ユーザーのguild(サーバー)情報自体も取得しようと思えばできる。(わかりづらいが、本家のdiscordでは参加してるサーバーのことをguildと呼んでいる)
config/initializers/omniauth.rb
のscope:
にguildsを描き足し、discord-omniauth自体に
info do
{
name: raw_info['username'],
email: raw_info['verified'] ? raw_info['email'] : nil,
guilds: access_token.get('users/@me/guilds').parsed,
image: "https://cdn.discordapp.com/avatars/#{raw_info['id']}/#{raw_info['avatar']}"
}
end
のguildsの項をかきたして、上記のuser.rbでauth['guilds']などでひっぱってこられる。
しかしgemを直接いじるのはいろいろと面倒があると思うので、ちょっと厳しいかもしれない。