Spring Boot maven工程如何实现扫码登录?
-
问题出现
以下是在工程里的相关配置
newBotConfiguration方法会生成自己定义的配置
我在登录的时候提示需要二维码登录
我找到了mirai-login-solver-sakura插件,但我不知道在SpringBoot中如何使用它?
需求
- 如何在SpringBoot工程中使用mirai-login-solver-sakura(mirai console插件)
- 如何实现二维码登录 或 短信验证码登录?
-
干脆用mirai-http-api得了(歪楼)
-
非程序员,医学生,我是这么写的代码,你可以参考,可扫码,可短信验证登陆,基于目前的2.15.0-M1: public static void login(Long botAccount, String botPassword) {
Configuration config = ConfigManager.getConfig();ClassLoader loader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(GlobalEventChannel.class.getClassLoader()); boolean loginByQR = config.getBoolean("loginByQR"); File workingDir = new File(ConfigManager.pluginDirectory, "bot"); if(!workingDir.exists()) workingDir.mkdirs(); BotFactory.BotConfigurationLambda botConfigurationLambda = botConfiguration -> { botConfiguration.setWorkingDir(workingDir); if (config.getBoolean("redirectBotLogToDirectory")) { botConfiguration.redirectBotLogToDirectory(); } if (config.getBoolean("noNetworkLog")) { botConfiguration.noNetworkLog(); } if (config.getBoolean("noBotLog")) { botConfiguration.noBotLog(); } botConfiguration.setProtocol(BotConfiguration.MiraiProtocol.valueOf(config.getString("bot-login-device"))); botConfiguration.setCacheDir(new File("cache")); botConfiguration.fileBasedDeviceInfo(); File deviceFile = new File(botConfiguration.getWorkingDir(), "device.json"); if (deviceFile.exists()) { botConfiguration.setDeviceInfo(bot1 -> DeviceInfo.from(deviceFile)); } }; bot = loginByQR ? BotFactory.INSTANCE.newBot(botAccount, BotAuthorization.byQRCode(), botConfigurationLambda) : BotFactory.INSTANCE.newBot(botAccount, botPassword, new BotConfiguration() {{ setWorkingDir(workingDir); if (config.getBoolean("redirectBotLogToDirectory")) { redirectBotLogToDirectory(); } if (config.getBoolean("noNetworkLog")) { noNetworkLog(); } if (config.getBoolean("noBotLog")) { noBotLog(); } //FixProtocolVersion.update(); setProtocol(MiraiProtocol.valueOf(config.getString("bot-login-device"))); setCacheDir(new File("cache")); fileBasedDeviceInfo(); File deviceFile = new File(getWorkingDir(), "device.json"); if (deviceFile.exists()) { setDeviceInfo(bot1 -> DeviceInfo.from(deviceFile)); } }}); bot.login(); Thread.currentThread().setContextClassLoader(loader); }
-
此回复已被删除! -
@abc408880155 确实可以用,不过我项获取二维码图片发送到前端验证
-
不明白前端,我还只简单学了学Java,研究了下mirai给的说明。不过,它的二维码图片估计得看他的源码是怎么发出来的,复写下应该可以。你如果折腾明白了,麻烦转告我下
-
-
@cssxsh nice……之前一直没看到这个,谢啦
-
@abc408880155 createQRCodeLoginListener来获取二维码。
// 自定义LoginSolver public class QqLoginSolver extends LoginSolver { private Object verification(Long qq, Object request) { QqSession qqSession = QqSessionManager.getQqSession(qq); Object[] code = new Object[1]; CountDownLatch latch = new CountDownLatch(1); // 定义一个CountDownLatch对象,用于等待code[0] qqSession.sendRequest(request, response -> { code[0] = response; latch.countDown(); }); try { latch.await(300000, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { // 错误处理 } return code[0]; } @Nullable @Override public Object onSolvePicCaptcha(@NotNull Bot bot, @NotNull byte[] bytes, @NotNull Continuation<? super String> continuation) { return verification(bot.getId(), bytes); } @Nullable @Override public Object onSolveSliderCaptcha(@NotNull Bot bot, @NotNull String url, @NotNull Continuation<? super String> continuation) { return verification(bot.getId(), url); } @NotNull @Override public QRCodeLoginListener createQRCodeLoginListener(@NotNull Bot bot) { return new QRCodeLoginListener() { @Override public void onStateChanged(@NotNull Bot bot1, @NotNull State state) throws LoginFailedException { if (state.name().equals("TIMEOUT")) throw new RuntimeException("二维码已失效"); } @Override public void onFetchQRCode(@NotNull Bot bot1, @NotNull byte[] bytes) { QqSessionManager.getQqSession(bot1.getId()).sendRequest(bytes, null); } }; } }
-
@2446694 谢谢!
-
@2446694
大佬,QqSession和 QqSessionManager我引不到,目前我只引了mirai-core-jvm这一个依赖,是不是还缺少了什么依赖? -
我使用的依赖是 mirai-core 这一个
以下是你提到的配置
QQSission
package com.session; import net.mamoe.mirai.Bot; import net.mamoe.mirai.BotFactory; import net.mamoe.mirai.auth.BotAuthorization; import net.mamoe.mirai.contact.*; import net.mamoe.mirai.event.EventChannel; import net.mamoe.mirai.event.events.BotEvent; import net.mamoe.mirai.utils.BotConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.function.Consumer; /** * ContactOrBot Contact 和 Bot 的公共接口 2.0 * OtherClient Bot 的其他客户端,如 “我的 iPad”,”我的电脑” 2.0 * Bot 机器人对象 2.0 * Contact 联系人对象,即所有的群,好友,陌生人,群成员等 2.0 * Group 群对象 2.0 * User 用户对象,即 “个人”. 包含好友,陌生人,群成员,临时会话用户 2.0 * Friend 好友对象 2.0 * Stranger 陌生人对象 2.0 * Member 群成员对象,属于一个 Group. 2.0 * NormalMember 普通群成员对象. 2.0 * AnonymousMember 匿名群成员对象. 2.0 */ public class QqSession { private static final Logger logger = LoggerFactory.getLogger(QqSession.class); private final Bot bot; private final Consumer<Object> doRequest; private Consumer<Object> doResponse; public QqSession(Long qq, String password, Consumer<Object> doRequest) { // 使用自定义配置 BotConfiguration botConfiguration = new QqBotConfiguration(qq); // 定义属性 this.bot = BotFactory.INSTANCE.newBot(qq, password, botConfiguration); // 验证信息处理 this.doRequest = doRequest; } public QqSession(Long qq, BotAuthorization credential, Consumer<Object> doRequest) { // 使用自定义配置 BotConfiguration botConfiguration = new QqBotConfiguration(qq); // 二维码登录 this.bot = BotFactory.INSTANCE.newBot(qq, credential, botConfiguration); // 验证信息处理 this.doRequest = doRequest; } public Bot getBot() { return this.bot; } public boolean login() { this.bot.login(); boolean isOnline = this.bot.isOnline(); if (isOnline) logger.info(this.bot.getId() + " 登录成功"); else logger.info(this.bot.getId() + " 登录失败"); return isOnline; } public boolean isOnline() { return this.bot.isOnline(); } public void close() { this.bot.close(); } public Long getQq() { return this.bot.getId(); } public ContactList<Friend> getFriends() { // 获取好友列表 return this.bot.getFriends(); } public ContactList<Group> getGroups() { // 获取群列表 return this.bot.getGroups(); } public Friend getFriend(Long id) { // 获取指定qq号好友 return this.bot.getFriend(id); } public Group getGroup(Long id) { // 根据群号获取群 return this.bot.getGroup(id); } public Stranger getStranger(Long id) { // 获取指定qq号陌生人 return this.bot.getStranger(id); } public ContactList<OtherClient> getOtherClients() { // 联系其他客户端 return this.bot.getOtherClients(); } public EventChannel<BotEvent> getEventChannel() { return this.bot.getEventChannel(); } public void sendRequest(Object request, Consumer<Object> doResponse) { this.doResponse = doResponse; // 发送验证请求 this.doRequest.accept(request); } public void sendResponse(String response) { // 响应验证码 doResponse.accept(response); } }
QqSessionManager
package com.session; import net.mamoe.mirai.auth.BotAuthorization; import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; public class QqSessionManager { private static final Map<Long, QqSession> sessionMap = new HashMap<>(); public static QqSession newQqSession(Long qq, Object credential, Consumer<Object> doRequest) { QqSession qqSession; if (credential instanceof BotAuthorization) qqSession = new QqSession(qq, (BotAuthorization) credential, doRequest); else if (credential instanceof String) qqSession = new QqSession(qq, (String) credential, doRequest); else throw new IllegalArgumentException("无效的credential"); sessionMap.put(qq, qqSession); return qqSession; } public static QqSession getQqSession(Long qq) { return sessionMap.get(qq); } public static void removeQqSession(Long qq) { sessionMap.get(qq).close(); sessionMap.remove(qq); } }
-
@2446694 在 Spring Boot maven工程如何实现扫码登录? 中说:
我使用的依赖是 mirai-core 这一个
以下是你提到的配置
QQSission
package com.session; import net.mamoe.mirai.Bot; import net.mamoe.mirai.BotFactory; import net.mamoe.mirai.auth.BotAuthorization; import net.mamoe.mirai.contact.*; import net.mamoe.mirai.event.EventChannel; import net.mamoe.mirai.event.events.BotEvent; import net.mamoe.mirai.utils.BotConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.function.Consumer; /** * ContactOrBot Contact 和 Bot 的公共接口 2.0 * OtherClient Bot 的其他客户端,如 “我的 iPad”,”我的电脑” 2.0 * Bot 机器人对象 2.0 * Contact 联系人对象,即所有的群,好友,陌生人,群成员等 2.0 * Group 群对象 2.0 * User 用户对象,即 “个人”. 包含好友,陌生人,群成员,临时会话用户 2.0 * Friend 好友对象 2.0 * Stranger 陌生人对象 2.0 * Member 群成员对象,属于一个 Group. 2.0 * NormalMember 普通群成员对象. 2.0 * AnonymousMember 匿名群成员对象. 2.0 */ public class QqSession { private static final Logger logger = LoggerFactory.getLogger(QqSession.class); private final Bot bot; private final Consumer<Object> doRequest; private Consumer<Object> doResponse; public QqSession(Long qq, String password, Consumer<Object> doRequest) { // 使用自定义配置 BotConfiguration botConfiguration = new QqBotConfiguration(qq); // 定义属性 this.bot = BotFactory.INSTANCE.newBot(qq, password, botConfiguration); // 验证信息处理 this.doRequest = doRequest; } public QqSession(Long qq, BotAuthorization credential, Consumer<Object> doRequest) { // 使用自定义配置 BotConfiguration botConfiguration = new QqBotConfiguration(qq); // 二维码登录 this.bot = BotFactory.INSTANCE.newBot(qq, credential, botConfiguration); // 验证信息处理 this.doRequest = doRequest; } public Bot getBot() { return this.bot; } public boolean login() { this.bot.login(); boolean isOnline = this.bot.isOnline(); if (isOnline) logger.info(this.bot.getId() + " 登录成功"); else logger.info(this.bot.getId() + " 登录失败"); return isOnline; } public boolean isOnline() { return this.bot.isOnline(); } public void close() { this.bot.close(); } public Long getQq() { return this.bot.getId(); } public ContactList<Friend> getFriends() { // 获取好友列表 return this.bot.getFriends(); } public ContactList<Group> getGroups() { // 获取群列表 return this.bot.getGroups(); } public Friend getFriend(Long id) { // 获取指定qq号好友 return this.bot.getFriend(id); } public Group getGroup(Long id) { // 根据群号获取群 return this.bot.getGroup(id); } public Stranger getStranger(Long id) { // 获取指定qq号陌生人 return this.bot.getStranger(id); } public ContactList<OtherClient> getOtherClients() { // 联系其他客户端 return this.bot.getOtherClients(); } public EventChannel<BotEvent> getEventChannel() { return this.bot.getEventChannel(); } public void sendRequest(Object request, Consumer<Object> doResponse) { this.doResponse = doResponse; // 发送验证请求 this.doRequest.accept(request); } public void sendResponse(String response) { // 响应验证码 doResponse.accept(response); } }
QqSessionManager
package com.session; import net.mamoe.mirai.auth.BotAuthorization; import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; public class QqSessionManager { private static final Map<Long, QqSession> sessionMap = new HashMap<>(); public static QqSession newQqSession(Long qq, Object credential, Consumer<Object> doRequest) { QqSession qqSession; if (credential instanceof BotAuthorization) qqSession = new QqSession(qq, (BotAuthorization) credential, doRequest); else if (credential instanceof String) qqSession = new QqSession(qq, (String) credential, doRequest); else throw new IllegalArgumentException("无效的credential"); sessionMap.put(qq, qqSession); return qqSession; } public static QqSession getQqSession(Long qq) { return sessionMap.get(qq); } public static void removeQqSession(Long qq) { sessionMap.get(qq).close(); sessionMap.remove(qq); } }
Controller层实现
@PostMapping("/login") public Result<Object> request(@RequestParam("qq") Long qq, @RequestParam(value = "pwd", required = false) String pwd) throws InterruptedException { Result<Object> result = new Result<>(); // 将url信息设置到result中 QqSession[] qqSession = new QqSession[]{QqSessionManager.getQqSession(qq)}; if (qqSession[0] == null || !qqSession[0].isOnline()) { CountDownLatch latch = new CountDownLatch(1); // 定义一个CountDownLatch对象,用于等待result.setData new Thread(() -> { if (pwd == null) { result.setCode(220); qqSession[0] = QqSessionManager.newQqSession(qq, BotAuthorization.byQRCode(), object -> { byte[] bytes = (byte[]) object; String base64Image = "data:image/png;base64," + Base64.getEncoder().encodeToString(bytes); result.setData(base64Image, "请扫码"); // 将图片设置到result中 latch.countDown(); }); } else { result.setCode(210); qqSession[0] = QqSessionManager.newQqSession(qq, pwd, object -> { if (object instanceof byte[]) { byte[] bytes = (byte[]) object; String base64Image = "data:image/png;base64," + Base64.getEncoder().encodeToString(bytes); result.setData(base64Image, "请处理验证码"); // 将图片设置到result中 } else result.setData(object, "请处理url"); // 将url信息设置到result中 latch.countDown(); }); } result.setCode(200).setData(qqSession[0].login(),"登录成功"); latch.countDown(); }).start(); latch.await(10000, TimeUnit.MILLISECONDS); // 调用CountDownLatch对象的await方法等待url信息被设置 } else { result.setCode(200).setData(qqSession[0].isOnline(), "已经登录过了"); } return result; // 返回result对象给前端 }
Result类
package com.domain; import java.util.HashMap; import java.util.Map; public class Result<T> { static { Result.codeMap = new HashMap<>(); Result.codeMap.put(100, "查询失败,没有找到相关数据"); Result.codeMap.put(110, "添加失败,无法添加该数据"); Result.codeMap.put(120, "删除失败,相关数据不存在"); Result.codeMap.put(130, "修改失败,相关数据不存在"); Result.codeMap.put(200, "登录失败"); Result.codeMap.put(210, "验证码失效"); Result.codeMap.put(220, "二维码失效"); Result.codeMap.put(230, "短信验证失效"); Result.codeMap.put(290, "登出失败"); Result.codeMap.put(900, "请求数据有误"); Result.codeMap.put(910, "系统繁忙,请稍后再试"); Result.codeMap.put(990, "发生未知的错误,暂时无法处理"); } private static Map<Integer, String> codeMap; private int code; private String msg; private T data; public Result() { } public Result(int code) { // 设置十位数上的值 this.code = code; this.msg = codeMap.get(code); } public int getCode() { return code; } public Result<T> setCode(int code) { this.code = code; this.msg = codeMap.get(code); return this; } public String getMsg() { return msg; } public Result<T> setErrorMsg(String errorMsg) { // 如果代码为0,则表示异常或失败,设置错误信息 if (this.code % 10 == 0) this.msg = errorMsg; return this; } public T getData() { return data; } public Result<T> setData(T data) { // 改变个位数上的值 if (notNone(data) && this.code / 100 != 9) { this.code = this.code / 10 * 10 + 1; this.msg = "操作成功"; } this.data = data; return this; } public Result<T> setData(T data, String msg) { // 改变个位数上的值 if (notNone(data) && this.code / 100 != 9) { this.code = this.code / 10 * 10 + 1; this.msg = msg; } this.data = data; return this; } private boolean notNone(Object value) { // Character(char(\u0000)) 会被 instanceof Number == 0 处理 return value instanceof Boolean ? (Boolean) value : value instanceof Number ? value != (Number) 0 : value instanceof String ? value != "" : value != null; } @Override public String toString() { return "Result{code=" + code + ", msg=" + msg + ", data=" + data + '}'; } }
-
-
@2446694
成功登录了,感谢大佬。 -
有没有simbot.boot框架加扫码的方法呢?