[RUBY] [Rails] Allow only people with specific server residents/specific roles of Discord to authenticate in sign-in

For those who want to create a service that only Discord residents want to use. Specifically, the method is to check the role of the user to see if it belongs to a server (there is also a method to get a list of servers in which the user is participating, so it will be described later). You need a bot account to get the role, so you need to invite the bot, but you can do it without any administrator privileges.

0. Create a Discord developer account and get a Client ID and bot token for OAuth2 authentication

Create a new application with New Application in Discord Developer Portal. Get Client ID and Client Secret for OAuth2 authentication. Callback settings can be set later.

Also, since you need a bot, create a bot in the same app and get a bot token.

There are quite a few detailed explanations here on other sites, so it's probably okay (although the Permission settings are confusing).

1. Install omniauth and omniauth-discord

Speaking of rails authentication, it is normal to use a gem called devise, but if you just create an account with OAuth2 authentication such as Discord, you do not need Devise. Omniauth can easily implement OAuth authentication for compatible sites by installing the distributed strategy.

The implementation of omniauth and omniauth-discord will be described in detail later, but basically omniauth (twitter/facebook/github) implementation summary can be done without any problem.

2. Install Discordrb

The gem required to play with Discord's bot relationship with rails is discordrb, so install this.

In addition, this gem seems to use a library called libsodium, and I was swayed by this guy in both the development stage and the production stage. Even after searching, there are quite a lot of people who find it difficult to do this. It seems that it is necessary for sound relations, but if you do not need it, you can ignore it. On heroku, https://github.com/xrisk/heroku-opus, https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest, https://github.com/challengee/heroku -Buildpack-libsodium is included in Buildpacks and it works, so please refer to it.

3. Use Discordrb API class

Assuming that the data of the user who signed up with the user model is acquired, play with app/models/user.rb.

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 class can get data using bot API, so user data including role information can be taken.

Basically, if you are a resident of a specific Discord server, you have at least the everyone role, so you have the same role ID as the server ID. So if you want to limit "I want only users who are subscribed to this channel to be able to log in", I think it's basically okay to check if the server ID is included in the roleID (I think so) But I'm sorry if it's different). Of course, since the role ID can be checked for each person who has it, restrictions can be placed only on people with operating authority, or only on residents who are given the role of everyone or higher.

If you give user information a column such as authority, and give it a value such as 10 for everyone, 30 for staff, etc., then you can use a simple conditional statement such as if @ user.authority> 29 for each page. Access restrictions can also be implemented.

By the way, if you want to get the user's guild (server) information directly, you can do it. (It's hard to understand, but in the original discord, the participating server is called guild)

Add guilds to scope: of config/initializers/omniauth.rb and add to discord-omniauth itself

ruby:Ruby/lib/ruby/gems/2.x.0/gems/omniauth-discord-1.0.0/lib/omniauth/strategies/discord.rb


      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

You can pull the guilds section of the above with auth ['guilds'] etc. in user.rb above.

However, it is troublesome to play with the gem directly, and as I mentioned earlier, if you check whether the server ID is included in the role ID, it will be the case in most cases, so pull the guild information. I don't think there is a need to come.

Recommended Posts

[Rails] Allow only people with specific server residents/specific roles of Discord to authenticate in sign-in
[IOS] To allow rotation of only a specific screen
Connect to Rails server with iPhone
Add class only to specific elements with V-for
One way to redirect_to with parameters in rails
How to use JQuery in js.erb of Rails6