Discord OAuth2授权以及机器人监听群事件

2024-03-12 10:52

本文主要是介绍Discord OAuth2授权以及机器人监听群事件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

下面文章讲解获取OAuth2授权整个流程,创建机器人,使用机器人监听工会(工会就是创建的服务器)成员变化等等,对接国外的都是需要VPN的哦,对接的时候记得提前准备。

创建应用

点击 此页面添加应用,,创建完成以后会生成应用名称,公钥,客户id等等,这些我们可以保存下来。这些应用会自动和我们的工会关联的。

创建机器人

在下面页面创建一个机器人,机器人会会生成自己的token,这个一定要保存好,注意机器人安全。


配置OAuth2

页面创建我们的OAuth2,重定向URL需要配置前端页面的URL,因为获取用户token需要重定向到前端页面,这个地方我们自定义配置即可,授权我们可以访问用户的一些功能权限。

将机器人加入我们的工会

 创建工会(服务器)直接在discord聊天页面创建就好了,这个就不多说了,那么我们如何将我们的机器人拉入到我们的服务器呢?

选择OAuth2,选择bot,勾选机器人的工会权限,然后下面会生成一个链接。

打开链接会出现下图内容,我们将我们的机器人加入到我们自己的服务器即可。 

我们通过上面的步骤成功的创建了我们的应用、工会和机器人,下面我们将介绍如何使用OAuth2相关功能以及操作机器人。

OAuth2功能实现

<!-- Discord4J  依赖 -->
<dependency><groupId>com.discord4j</groupId><artifactId>discord4j-core</artifactId><version>3.2.1</version>
</dependency><dependency><groupId>net.dv8tion</groupId><artifactId>JDA</artifactId><version>5.0.0-beta.12</version>
</dependency>

根据配置的OAuth2页面生成相关的链接,用户点击授权以后回调到前端页面,页面会带有code以及state参数,code我们用来换取token,state授权页面我们传什么参数过去会给我们带回来的一个参数,授权类似与下面的地址。

https://discord.com/oauth2/authorize?client_id=1215207180614246411&state=%E9%9A%8F%E6%9C%BA%E5%8F%82%E6%95%B0&response_type=code&redirect_uri=http%3A%2F%2F9cxuu6.natappfree.cc%2Fdiscord%2FgetDiscordByCode&scope=identify+guilds+email+guilds.join+connections+guilds.members.read
 

根据token交互用户数据

拿到token以后我们可以查询用户的信息,用户工会情况等等。

package com.odcchina.server.api;import com.odcchina.common.config.BaseComponent;
import com.odcchina.server.dto.DiscordDto;
import com.odcchina.server.service.DiscordService;
import com.odcchina.server.service.GuildEvent;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.requests.GatewayIntent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;
import java.util.Map;@Slf4j
@RestController
@RequestMapping("/discord")
@Api(tags = "discord服务")
@Transactional(isolation = Isolation.READ_COMMITTED)
public class DiscordController extends BaseComponent {@Autowiredprivate DiscordService discordService;/*** 授权回调code* @param code* @return*/@GetMapping("getDiscordByCode")@ApiOperation("获取discord的Code")public Map<String, String> getTuiteCode(String code) {Map<String, String> map = new HashMap<>();//根据code换取tokenDiscordDto discordDto = discordService.getToken(code,null);map.put("code", code);map.put("access_token", discordDto.getAccessToken());map.put("refresh_token", discordDto.getRefreshToken());return map;}@GetMapping("findLaborUnionList")@ApiOperation("查询我的工会列表")public Map<String, String> findLaborUnionList(String token) {Map<String, String> map = new HashMap<>();try {discordService.findLaborUnionList(token);} catch (Exception e) {throw new RuntimeException(e);}return map;}@GetMapping("findUserLaborUnion")@ApiOperation("查询用户是否存在工会里面")public Map<String, String> findUserLaborUnion(String token,String guildId) {Map<String, String> map = new HashMap<>();try {discordService.findUserLaborUnion(token,guildId);} catch (Exception e) {throw new RuntimeException(e);}return map;}@GetMapping("findUser")@ApiOperation("查询用户信息")public Map<String, String> findUser(String token) {Map<String, String> map = new HashMap<>();try {discordService.findUser(token);} catch (Exception e) {throw new RuntimeException(e);}return map;}}
package com.odcchina.server.service;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.scribejava.apis.DiscordApi;
import com.odcchina.server.config.DiscordConfig;
import com.odcchina.server.dto.DiscordDto;
import com.odcchina.server.dto.DiscordlaborUnionDto;
import com.odcchina.server.dto.UserDto;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;@Slf4j
@Service
public class DiscordService {/*** form表单提交* @param url* @param map* @return*/public DiscordDto doPostForm(String url, Map<String, Object> map) {String strResult = "";CloseableHttpClient client = HttpClients.createDefault();HttpPost httpPost = new HttpPost(url);httpPost.setHeader("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");List<BasicNameValuePair> paramPairs = new ArrayList<>();Set<String> keySet = map.keySet();for (String key : keySet) {Object val = map.get(key);paramPairs.add(new BasicNameValuePair(key, val.toString()));}UrlEncodedFormEntity entity;try {// 4. 将参数设置到entity对象中entity = new UrlEncodedFormEntity(paramPairs, "UTF-8");// 5. 将entity对象设置到httppost对象中httpPost.setEntity(entity);// 6. 发送请求并回去响应CloseableHttpResponse resp = client.execute(httpPost);try {HttpEntity respEntity = resp.getEntity();strResult = EntityUtils.toString(respEntity, "UTF-8");JSONObject json = JSON.parseObject(strResult.toString());Object access_token = json.get("access_token");Object refresh_token = json.get("refresh_token");Object token_type = json.get("token_type");Object expires_in = json.get("expires_in");if(access_token == null || refresh_token == null){return null;}DiscordDto discordDto = new DiscordDto();discordDto.setAccessToken(access_token.toString());discordDto.setRefreshToken(refresh_token.toString());discordDto.setTokenType(token_type.toString());discordDto.setExpiresIn(Integer.parseInt(expires_in.toString()));return discordDto;} finally {resp.close();}} catch (ClientProtocolException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {// 10. 关闭连接,释放资源try {client.close();} catch (Exception e) {e.printStackTrace();}}return null;}/*** 根据code换取token** @param code* @return*/public DiscordDto getToken(String code,String refreshToken) {try {Map<String, Object> formData = new HashMap<>();if(!StringUtils.isBlank(code)){formData.put("grant_type", "authorization_code");formData.put("code", code);}if(!StringUtils.isBlank(refreshToken)){formData.put("refresh_token", refreshToken);formData.put("grant_type", "refresh_token");}//TODO 重定向配置的URL,一定要和重定向里面的地址保持一致formData.put("redirect_uri", 重定向配置的地址URL");formData.put("client_id", DiscordConfig.CLIENT_ID);formData.put("client_secret", DiscordConfig.CLIENT_SECRET);// 创建URL对象DiscordDto discordDto = this.doPostForm("https://discord.com/api/oauth2/token",formData);return discordDto;} catch (Exception e) {throw new RuntimeException(e);}}/*** 获取用户的所有服务器* @param token* @return*/public List<DiscordlaborUnionDto> findLaborUnionList(String token) {try {// 设置请求URL和Bearer TokenCloseableHttpClient httpClient = HttpClientBuilder.create().build();HttpGet httpPost = new HttpGet("https://discord.com/api/v9/users/@me/guilds");httpPost.setHeader("Content-Type", "application/json;charset=utf8");httpPost.setHeader("Authorization", "Bearer " + token);CloseableHttpResponse response = null;// 由客户端执行(发送)Post请求response = httpClient.execute(httpPost);// 从响应模型中获取响应实体HttpEntity responseEntity = response.getEntity();if (response.getStatusLine().getStatusCode() == 200 && responseEntity != null) {String responseJson = EntityUtils.toString(responseEntity);JSONArray jsonArray = JSON.parseArray(responseJson);List<DiscordlaborUnionDto> jsonArrayToStringList = JSONObject.parseArray(jsonArray.toJSONString(),DiscordlaborUnionDto.class);return jsonArrayToStringList;}} catch (Exception e) {e.printStackTrace();}return null;}public Boolean findUserLaborUnion(String token, String guildId) {try {// 设置请求URL和Bearer TokenCloseableHttpClient httpClient = HttpClientBuilder.create().build();HttpGet httpPost = new HttpGet("https://discord.com/api/v9/users/@me/guilds/" + guildId+"/member");httpPost.setHeader("Content-Type", "application/json;charset=utf8");httpPost.setHeader("Authorization", "Bearer " + token);CloseableHttpResponse response = null;// 由客户端执行(发送)Post请求response = httpClient.execute(httpPost);// 从响应模型中获取响应实体HttpEntity responseEntity = response.getEntity();if (response.getStatusLine().getStatusCode() == 200 && responseEntity != null) {String responseJson = EntityUtils.toString(responseEntity);JSONObject jsonArray = JSON.parseObject(responseJson);if(jsonArray.get("user") != null){return true;}}} catch (Exception e) {e.printStackTrace();}return false;}/*** 查询用户信息* @param token* @return*/public UserDto findUser(String token) {try {// 设置请求URL和Bearer TokenCloseableHttpClient httpClient = HttpClientBuilder.create().build();HttpGet httpPost = new HttpGet("https://discord.com/api/v9/users/@me");httpPost.setHeader("Content-Type", "application/json;charset=utf8");httpPost.setHeader("Authorization", "Bearer " + token);CloseableHttpResponse response = null;// 由客户端执行(发送)Post请求response = httpClient.execute(httpPost);// 从响应模型中获取响应实体HttpEntity responseEntity = response.getEntity();if (response.getStatusLine().getStatusCode() == 200 && responseEntity != null) {String responseJson = EntityUtils.toString(responseEntity);JSONObject jsonArray = JSON.parseObject(responseJson);UserDto userDto = JSON.toJavaObject(jsonArray, UserDto.class);return userDto;}} catch (Exception e) {e.printStackTrace();}return null;}}
package com.odcchina.server.dto;import lombok.Data;
import lombok.experimental.Accessors;@Data
@Accessors(chain = true)
public class DiscordDto {/*** 访问令牌*/private String accessToken;/*** 刷新令牌*/private String refreshToken;/*** 认证方式 Bearer*/private String tokenType;/*** 过期时间 (秒)*/private Integer expiresIn;}
package com.odcchina.server.dto;import lombok.Data;
import lombok.experimental.Accessors;/*** 获取工会列表*/
@Data
@Accessors(chain = true)
public class DiscordlaborUnionDto {/*** 工会ID*/public String id;/*** 工会名称*/public String name;}
package com.odcchina.server.dto;import lombok.Data;
import lombok.experimental.Accessors;@Data
@Accessors(chain = true)
public class DiscordUserDto {/*** 服务器ID*/private String guildId;/*** 服务器名称*/private String guildName;/*** 用户ID*/private String userId;/*** 用户名称*/private String userName;}
package com.odcchina.server.config;/*** Discord相关配置*/
public class DiscordConfig {/*** 客户id和客户私钥*/public static final String CLIENT_ID = "111111";public static final String CLIENT_SECRET = "nL8gLAmZEFZYtQQ2mqE3tEYWC111111";public static final String PUBLIC_CLIENT_SECRET = "feca6db06a1af3c5ebff8fb3710213b86651f6401623d103a5111111";public static final String TOKEN_ENDPOINT = "https://discord.com/api/oauth2/token";
}

使用机器人监听工会会员变动情况

工会会员新加入,退出等情况监听,前期我们需要开启下面这些功能,不然机器人无法监听:

    @GetMapping("botMonitor")@ApiOperation("开启机器人监听服务")public Map<String, String> botMonitor() {//启动机器人,监听成员事件try {//这里是机器人的token的,注意下String botToken = "1111.Gh00hD.1111";JDABuilder builder = JDABuilder.createDefault(botToken);//添加事件监听器builder.addEventListeners(new GuildEvent());//builder.useSharding(int shardId, int shardTotal)//工会成员 GUILD_MEMBERS TODO 这个地方在机器人里面有个选项需要开启,不然无法调用builder.enableIntents(GatewayIntent.GUILD_MEMBERS);builder.build();} catch (Exception e) {e.printStackTrace();}

当我们启动以后我们的机器人就会在线,由于我没有启动监听,所以我们的机器人在离线中的:

package com.odcchina.server.service;import com.odcchina.server.dto.DiscordUserDto;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.guild.GuildLeaveEvent;
import net.dv8tion.jda.api.events.guild.invite.GuildInviteCreateEvent;
import net.dv8tion.jda.api.events.guild.invite.GuildInviteDeleteEvent;
import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent;
import net.dv8tion.jda.api.events.guild.member.GuildMemberRemoveEvent;
import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleAddEvent;
import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleRemoveEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import javax.annotation.Nonnull;public class GuildEvent extends ListenerAdapter {@Overridepublic void onGuildInviteCreate(@Nonnull GuildInviteCreateEvent event) {//一个邀请被创建了}@Overridepublic void onGuildInviteDelete(@Nonnull GuildInviteDeleteEvent event) {//一个邀请被删除了}@Overridepublic void onGuildMemberJoin(@Nonnull GuildMemberJoinEvent event) {//有新成员进入公会Guild guild = event.getGuild();User user = event.getUser();DiscordUserDto discordUserDto = new DiscordUserDto();discordUserDto.setGuildId(guild.getId());discordUserDto.setGuildName(guild.getName());discordUserDto.setUserId(user.getId());discordUserDto.setUserName(user.getName());}@Overridepublic void onGuildLeave(@Nonnull GuildLeaveEvent event) {//有老成员离开公会}@Overridepublic void onGuildMemberRemove(@Nonnull GuildMemberRemoveEvent event) {//有成员被移除公会}@Overridepublic void onGuildMemberRoleAdd(@Nonnull GuildMemberRoleAddEvent event) {//公会成员添加角色}@Overridepublic void onGuildMemberRoleRemove(@Nonnull GuildMemberRoleRemoveEvent event) {//公会成员移除角色}
}

机器人其他功能调用,比如查询邀请信息,查询邀请我的频道会员

https://discord.com/api/v9/channels/工会ID/invites

关于其他机器人功能实现可以参考下面的文档,大佬写的很详细,点这里 

这篇关于Discord OAuth2授权以及机器人监听群事件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/801039

相关文章

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

禁止平板,iPad长按弹出默认菜单事件

通过监控按下抬起时间差来禁止弹出事件,把以下代码写在要禁止的页面的页面加载事件里面即可     var date;document.addEventListener('touchstart', event => {date = new Date().getTime();});document.addEventListener('touchend', event => {if (new

FreeRTOS内部机制学习03(事件组内部机制)

文章目录 事件组使用的场景事件组的核心以及Set事件API做的事情事件组的特殊之处事件组为什么不关闭中断xEventGroupSetBitsFromISR内部是怎么做的? 事件组使用的场景 学校组织秋游,组长在等待: 张三:我到了 李四:我到了 王五:我到了 组长说:好,大家都到齐了,出发! 秋游回来第二天就要提交一篇心得报告,组长在焦急等待:张三、李四、王五谁先写好就交谁的

基于树梅派的视频监控机器人Verybot

最近这段时间做了一个基于树梅派 ( raspberry pi ) 的视频监控机器人平台 Verybot ,现在打算把这个机器人的一些图片、视频、设计思路进行公开,并且希望跟大家一起研究相关的各种问题,下面是两张机器人的照片:         图片1:                   图片2                    这个平台的基本组成是:

【经验交流】修复系统事件查看器启动不能时出现的4201错误

方法1,取得『%SystemRoot%\LogFiles』文件夹和『%SystemRoot%\System32\wbem』文件夹的权限(包括这两个文件夹的所有子文件夹的权限),简单点说,就是使你当前的帐户拥有这两个文件夹以及它们的子文件夹的绝对控制权限。这是最简单的方法,不少老外说,这样一弄,倒是解决了问题。不过对我的系统,没用; 方法2,以不带网络的安全模式启动,运行命令行,输入“ne

BT天堂网站挂马事件后续:“大灰狼”远控木马分析及幕后真凶调查

9月初安全团队披露bt天堂网站挂马事件,该网站被利用IE神洞CVE-2014-6332挂马,如果用户没有打补丁或开启安全软件防护,电脑会自动下载执行大灰狼远控木马程序。 鉴于bt天堂电影下载网站访问量巨大,此次挂马事件受害者甚众,安全团队专门针对该木马进行严密监控,并对其幕后真凶进行了深入调查。 一、“大灰狼”的伪装 以下是10月30日一天内大灰狼远控的木马样本截图,可以看到该木马变种数量不

【Shiro】Shiro 的学习教程(二)之认证、授权源码分析

目录 1、背景2、相关类图3、解析3.1、加载、解析阶段3.2、认证阶段3.3、授权阶段 1、背景 继上节代码,通过 debug 进行 shiro 源码分析。 2、相关类图 debug 之前,先了解下一些类的结构图: ①:SecurityManager:安全管理器 DefaultSecurityManager: RememberMeManager:实现【记住我】功能

react笔记 8-19 事件对象、获取dom元素、双向绑定

1、事件对象event 通过事件的event对象获取它的dom元素 run=(event)=>{event.target.style="background:yellowgreen" //event的父级为他本身event.target.getAttribute("aid") //这样便获取到了它的自定义属性aid}render() {return (<div><h2>{

react笔记 8-18 事件 方法 定义方法 获取/改变数据 传值

1、定义方法并绑定 class News extends React.Component {constructor(props) {super(props)this.state = {msg:'home组件'}}run(){alert("我是一个run") //方法写在类中}render() {return (<div><h2>{this.state.msg}</h2><button onCli

【Qt】定时器事件

定时器事件 在之前学习QTimer中实现了定时器的功能,而在QTimer背后是QTimerEvent定时器事件进行支撑的。在QObject中提供了一个timeEvent这个函数。 startTimer启动定时器killTimer关闭定时器 Qt 中在进⾏窗⼝程序的处理过程中,经常要周期性的执⾏某些操作,或者制作⼀些动画效果,使⽤定 时器就可以实现。所谓定时器就是在间隔⼀定时间后,去执⾏某⼀