Java实现微信登录

2023-10-27

Java实现微信登录

代码实现微信授权
简单来说,微信授权分为四步:
1.授权登录接口,生成一个二维码在页面中。
2.用户点击授权成功后自动获取code。
3.浏览器自动利用code访问回调接口。
4.在回调接口中利用code登录,appId.appSecret进行登录获取token。
5.利用4获取的token再次访问接口INFO_URL 获取用户微信信息
6.再根据用户微信消息,进行本地信息存储,生成token,并将权限角色等信息返回至前端
7.至此整个微信登录过程结束

一.首先获取微信登录跳转地址

/**
     * 登录地址
     */
    private final static String LOGIN_URL = "https://open.weixin.qq.com/connect/qrconnect?" +
            "appid={appId}&" +
            "redirect_uri={redirect}&" +
            "response_type=code&" +
            "scope=snsapi_login&" +
            "state={state}";

    /**
     * 获取微信登录跳转地址
     * @return
     */
    @RequestMapping(value = "/api/common/wx/get-url", method = { RequestMethod.POST})
    @ApiOperation(value = "构建PC端微信登录地址", notes = "获取地址后直接跳转到登录地址,用户进行扫码登录")
    public ApiRest<WxUrlRespDTO> getUrl(@RequestBody WxUrlReqDTO reqDTO) {

        // state为登录跳转标识,可以跳转到h5页面
        String url = LOGIN_URL
                .replace("{appId}", wechatConfig.getSiteAppId())
                // 统一跳转地址
                .replace("{redirect}", baseConfig.getLoginRedirect())
                .replace("{state}", reqDTO.getState());

        WxUrlRespDTO respDTO = new WxUrlRespDTO();
        respDTO.setUrl(url);
        return success(respDTO);
    }

二.扫码成功后会回调该redirect的url

即 “/api/common/wx/redirect” 该回调接口地址

/**
     * 网站的微信登录跳转
     * @param code
     * @return
     */
    @GetMapping("/api/common/wx/redirect")
    @ApiOperation(value = "微信PC端登录回调地址")
    public ApiRest<SysUserLoginDTO> webRedirect(HttpServletResponse response, @RequestParam("code") String code,
                                                @RequestParam("state") String state) throws IOException {
        // 获取会话
        SysUserLoginDTO respDTO = wxLoginService.webLogin(
                wechatConfig.getSiteAppId(),
                wechatConfig.getSiteAppSecret(),
                code);
        String redirect = "";
        // 跳转到H5版本
        if(PlatformType.H5.equals(state)){
            redirect = baseConfig.getLoginSyncH5();
        }
        // 跳转到PC版本
        if(PlatformType.PC.equals(state)){
            redirect = baseConfig.getLoginSyncPc();
        }
        // 替换地址
        redirect = redirect
                .replace("{token}", respDTO.getToken())
                .replace("{roleType}", String.valueOf(respDTO.getRoleType()));
        if(StringUtils.isBlank(redirect)){
            return super.failure("同步登录参数错误或跳转地址未配置!");
        }
        response.sendRedirect(redirect);
        return null;
    }

会将扫码授权登录成功时返回的code一并携带,请求该回调地址

在该回调接口中,
// 获取会话wxLoginService.webLogin(wechatConfig.getSiteAppId(),wechatConfig.getSiteAppSecret(), code);
通过该方法真正获取微信相关信息

三.通过该方法wxLoginService.webLogin真正获取本人微信等相关信息

@Override
    public SysUserLoginDTO webLogin(String appId, String secret, String code) {
        //登录成功获取本人微信的相关信息
        WxInfoRespDTO rest = LoginUtils.requestInfo(appId, secret, code);

        // 登录并返回
        return sysUserService.loginByThird(LoginType.WECHAT, rest.getUqId(), rest.getNickName(), rest.getHeadimgurl());
    }

3.1 首先通过该appId,sercet,code,获取微信登录的token信息

    /**
     * 获取AccessToken
     */
    private static final String ACCESS_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={appId}&secret={appSecret}&code={code}&grant_type=authorization_code";

/**
     * 获取accessToken
     * @param appId
     * @param appSecret
     * @param code
     * @return
     */
    public static WxTokenRespDTO requestAccess(String appId, String appSecret, String code){

        // 构建完整请求URL
        String url = ACCESS_URL.replace("{appId}", appId)
                .replace("{appSecret}", appSecret)
                .replace("{code}", code);

        // 获得返回JSON
        String json = HttpClientUtil.getJson(url, null, null);

        log.info(json);

        // 转换为登录结果
        WxTokenRespDTO rest = JSON.parseObject(json, WxTokenRespDTO.class);

        return rest;
    }

3.2 利用该token再次请求获取微信用户个人相关信息

/**
     * 获取用户信息接口
     */
    private static final String INFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token={token}&openid={openid}";
    /**
     * 获取用户头像昵称等内容
     * @param appId
     * @param appSecret
     * @return
     */
    public static WxInfoRespDTO requestInfo(String appId, String appSecret, String code){

        // 获取accessToken
        WxTokenRespDTO token = requestAccess(appId, appSecret, code);

        // 获取用户信息
        String url = INFO_URL
                .replace("{token}", token.getAccessToken())
                .replace("{openid}", token.getOpenid());
		//发送httpGet请求
        String json = HttpClientUtil.getJson(url, null, null);

		//解析json结果 转化为Java对象
        WxInfoRespDTO rest =  JSON.parseObject(json, WxInfoRespDTO.class);

        return rest;
    }

WxInfoRespDTO 从微信中获取的用户信息:

public class WxInfoRespDTO extends BaseDTO {

    @ApiModelProperty(value = "会话标识", required=true)
    private String openId;

    @ApiModelProperty(value = "昵称", required=true)
    private String nickName;

    @ApiModelProperty(value = "性别", required=true)
    private Integer sex;

    @ApiModelProperty(value = "省份", required=true)
    private String province;

    @ApiModelProperty(value = "市", required=true)
    private String city;

    @ApiModelProperty(value = "国家", required=true)
    private String country;

    @ApiModelProperty(value = "头像地址", required=true)
    private String headimgurl;

    @ApiModelProperty(value = "头像地址", required=true)
    private String unionid;

    @ApiModelProperty(value = "头像地址", required=true)
    private List<String> privilege;

拿到微信登录后的相关信息后,进行本项目的登录

四.本项目微信登录后业务代码

@Override
    public SysUserLoginDTO loginByThird(String loginType, String openId, String nickName, String avatar) {

        String userId = sysUserBindService.findBind(loginType, openId);

        // 不存在,创建新的用户
        if (StringUtils.isBlank(userId)) {
            // 随机产生数据
            SysUserLoginDTO dto = this.saveAndLogin(
                    RandomStringUtils.randomAlphabetic(16),
                    "A01",
                    nickName,
                    avatar,
                    RandomStringUtils.randomAlphanumeric(32));
            // 建立绑定关系
            sysUserBindService.save(false, dto.getId(), loginType, openId);
            return dto;
        }
        // 校验用户状态&密码
        SysUser user = this.getById(userId);
        return this.checkAndLogin(user, null);
    }
    
    /**
     * 用户登录校验
     *
     * @param user
     */
    private SysUserLoginDTO checkAndLogin(SysUser user, String password) {

        if (user == null) {
            throw new ServiceException(ApiError.ERROR_90010001);
        }
        // 被禁用
        if (UserState.DISABLED.equals(user.getState())) {
            throw new ServiceException(ApiError.ERROR_90010005);
        }
        // 待审核
        if (UserState.AUDIT.equals(user.getState())) {
            throw new ServiceException(ApiError.ERROR_90010006);
        }
        if (!StringUtils.isBlank(password)) {
            boolean pass = PassHandler.checkPass(password, user.getSalt(), user.getPassword());
            if (!pass) {
                throw new ServiceException(ApiError.ERROR_90010002);
            }
        }
        return this.setToken(user);
    }

生成用户的token存储并将用户角色权限等信息,返回至前端

/**
     * 保存会话信息
     *
     * @param user
     * @return
     */
    @Override
    public SysUserLoginDTO setToken(SysUser user) {
        // 获取一个用户登录的信息
        String key = Constant.USER_NAME_KEY + user.getUserName();
        String json = redisService.getString(key);
        if (!StringUtils.isBlank(json)) {
            // 删除旧的会话
            redisService.del(key);
        }
        SysUserLoginDTO respDTO = new SysUserLoginDTO();
        BeanMapper.copy(user, respDTO);
        // 正常状态才登录
        if(UserState.NORMAL.equals(user.getState())){
            // 根据用户生成Token
            String token = JwtUtils.sign(user.getUserName());
            respDTO.setToken(token);
            // 添加角色信息
            this.fillRoleData(respDTO);
            // 权限表,用于前端控制按钮
            List<String> permissions = sysUserRoleService.findUserPermission(user.getId());
            respDTO.setPermissions(permissions);
            // 保存如Redis
            redisService.set(key, JSON.toJSONString(respDTO));
        }
        return respDTO;
    }

到此整个微信登录过程结束

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java实现微信登录 的相关文章

  • Java 中等效的并行扩展

    我在 Net 开发中使用并行扩展有一些经验 但我正在考虑在 Java 中做一些工作 这些工作将受益于易于使用的并行库 JVM 是否提供任何与并行扩展类似的工具 您应该熟悉java util concurrent http java sun
  • Grails 3.x bootRun 失败

    我正在尝试在 grails 3 1 11 中运行一个项目 但出现错误 失败 构建失败并出现异常 什么地方出了错 任务 bootRun 执行失败 进程 命令 C Program Files Java jdk1 8 0 111 bin java
  • Java new Date() 打印

    刚刚学习 Java 我知道这可能听起来很愚蠢 但我不得不问 System out print new Date 我知道参数中的任何内容都会转换为字符串 最终值是 new Date 返回对 Date 对象的引用 那么它是如何打印这个的呢 Mo
  • 为什么 i++ 不是原子的?

    Why is i Java 中不是原子的 为了更深入地了解 Java 我尝试计算线程中循环的执行频率 所以我用了一个 private static int total 0 在主课中 我有两个线程 主题 1 打印System out prin
  • 在 java 类和 android 活动之间传输时音频不清晰

    我有一个android活动 它连接到一个java类并以套接字的形式向它发送数据包 该类接收声音数据包并将它们扔到 PC 扬声器 该代码运行良好 但在 PC 扬声器中播放声音时会出现持续的抖动 中断 安卓活动 public class Sen
  • Android:捕获的图像未显示在图库中(媒体扫描仪意图不起作用)

    我遇到以下问题 我正在开发一个应用程序 用户可以在其中拍照 附加到帖子中 并将图片保存到外部存储中 我希望这张照片也显示在图片库中 并且我正在使用媒体扫描仪意图 但它似乎不起作用 我在编写代码时遵循官方的Android开发人员指南 所以我不
  • 加速代码 - 3D 数组

    我正在尝试提高我编写的一些代码的速度 我想知道从 3d 整数数组访问数据的效率如何 我有一个数组 int cube new int 10 10 10 我用价值观填充其中 然后我访问这些值数千次 我想知道 由于理论上所有 3d 数组都存储在内
  • 列出jshell中所有活动的方法

    是否有任何命令可以打印当前 jshell 会话中所有新创建的方法 类似的东西 list但仅适用于方法 您正在寻找命令 methods all 它会打印所有方法 包括启动 JShell 时添加的方法 以及失败 被覆盖或删除的方法 对于您声明的
  • 反射找不到对象子类型

    我试图通过使用反射来获取包中的所有类 当我使用具体类的代码 本例中为 A 时 它可以工作并打印子类信息 B 扩展 A 因此它打印 B 信息 但是当我将它与对象类一起使用时 它不起作用 我该如何修复它 这段代码的工作原理 Reflection
  • Liferay ClassNotFoundException:DLFileEntryImpl

    在我的 6 1 0 Portal 实例上 带有使用 ServiceBuilder 和 DL Api 的 6 1 0 SDK Portlet 这一行 DynamicQuery query DynamicQueryFactoryUtil for
  • 斯坦福 NLP - 处理文件列表时 OpenIE 内存不足

    我正在尝试使用斯坦福 CoreNLP 中的 OpenIE 工具从多个文件中提取信息 当多个文件 而不是一个 传递到输入时 它会给出内存不足错误 All files have been queued awaiting termination
  • 为什么HashMap不能保证map的顺序随着时间的推移保持不变

    我在这里阅读有关 Hashmap 和 Hashtable 之间的区别 http javarevisited blogspot sg 2010 10 difference Between hashmap and html http javar
  • 总是使用 Final?

    我读过 将某些东西做成最终的 然后在循环中使用它会带来更好的性能 但这对一切都有好处吗 我有很多地方没有循环 但我将 Final 添加到局部变量中 它会使速度变慢还是仍然很好 还有一些地方我有一个全局变量final 例如android Pa
  • 如何在 javadoc 中使用“<”和“>”而不进行格式化?

    如果我写
  • 仅将 char[] 的一部分复制到 String 中

    我有一个数组 char ch 我的问题如下 如何将 ch 2 到 ch 7 的值合并到字符串中 我想在不循环 char 数组的情况下实现这一点 有什么建议么 感谢您花时间回答我的问题 Use new String value offset
  • Android 中麦克风的后台访问

    是否可以通过 Android 手机上的后台应用程序 服务 持续监控麦克风 我想做的一些想法 不断聆听背景中的声音信号 收到 有趣的 音频信号后 执行一些网络操作 如果前台应用程序需要的话 后台应用程序必须能够智能地放弃对麦克风的访问 除非可
  • 声明的包“”与预期的包不匹配

    我可以编译并运行我的代码 但 VSCode 中始终显示错误 早些时候有一个弹出窗口 我不记得是什么了 我点击了 全局应用 从那以后一直是这样 Output is there but so is the error The declared
  • 获取 JVM 上所有引导类的列表?

    有一种方法叫做findBootstrapClass对于一个类加载器 如果它是引导的 则返回一个类 有没有办法找到类已经加载了 您可以尝试首先通过例如获取引导类加载器呼叫 ClassLoader bootstrapLoader ClassLo
  • 捕获的图像分辨率太大

    我在做什么 我允许用户捕获图像 将其存储到 SD 卡中并上传到服务器 但捕获图像的分辨率为宽度 4608 像素和高度 2592 像素 现在我想要什么 如何在不影响质量的情况下获得小分辨率图像 例如我可以获取或设置捕获的图像分辨率为原始图像分
  • 按日期对 RecyclerView 进行排序

    我正在尝试按日期对 RecyclerView 进行排序 但我尝试了太多的事情 我不知道现在该尝试什么 问题就出在这条线上适配器 notifyDataSetChanged 因为如果我不放 不会显示错误 但也不会更新 recyclerview

随机推荐

  • 内网安全:WMI协议与SMB协议横向移动

    目录 网络拓扑图 网络环境说明 WMI协议 SMB协议 域内信息收集 WMI协议 横向移动 利用方式一 wmic命令 利用方式一 cscript 利用方式一 impacket SMB协议 横向移动 利用方式一 psexec 利用方式二 ps
  • 1年多经验的 Java 开发,该如何提升自己比较好?

    中级Java开发岗位职责 负责研发公司应用软件的模块设计 开发和交付 负责编码 单元测试 按照功能组件的详细设计 对其他软件工程师的代码进行审核 参与新知识的学习和培训 参与业务相关的需求评审 编写技术文档设计 中级Java开发的岗位要求
  • Vue中的绑定样式

    绑定样式 1 class样式 写法 class xxx xxx可以是字符串 对象 数组 字符串写法适用于 类名不确定 要动态获取 对象写法适用于 要绑定多个样式 个数不确定 名字也不确定 数组写法适用于 要绑定多个样式 个数确定 名字也确定
  • 测试网络连通性

    测试网络连通性的方式 ssh v p 端口 root IP curl ip 端口 nc v IP 端口
  • SQL Server 数据库之变量

    变量 1 变量概述 1 1 常规标识符 1 2 分隔标识符 2 局部变量 2 1 局部变量声明 2 2 局部变量赋值 2 3 变量显示 3 全局变量 3 1 全局变量注意事项 3 2 常用的全局变量 4 注释符 5 运算符 5 1 算术运算
  • 【CV】从 YOLO 到 YOLOv8:追踪目标检测算法的演变

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • 使用Flutter和Arduino控制设备

    硬件 配置Arduino IDE Arduino服务器 首先 让TCP服务器运行并测试其是否正常运行 创建一个WiFi服务器对象 现在让我们填写setup 函数 将串行连接配置为115 200 bps的速度 等待一秒钟以确保串行连接已初始化
  • JMeter压力测试实例操作

    1 脚本录制 脚本录制 JMeter启用WEB代理 浏览器把代理上网设置为JMeter所在的IP地址 自己电脑就是127 0 0 1代理端口默认8080 至于浏览器修改代理上网服务器 不做截图 Jmeter 运行在目录 apache jme
  • Qt 的几个常用部件 -- QFrame

    文章目录 基本信息 公共类型 可用来设置的 详细描述 可以处理的事件 基本信息 头文件 include
  • 微信小程序——订阅消息与微信公众号模板消息

    订阅消息 一次性订阅消息 某个按钮 并且只能是用户自己就手动点击的 操作调起来这个允许授权弹窗 允许通知之后也只能发送一次消息 即便点上 总是保持一上选择 不再询问 也只是在下次点击同一个按钮时默认允许发送消息 不是可以一直发送消息的 使用
  • python文件处理方式

    python文件处理方式 file open D pythonText txt r encoding UTF 8 print file lt io TextIOWrapper name D pythonText txt mode r enc
  • IntelliJ IDEA (Ultimate Edition)2021.1配置javaFX8(Mac Pro) 踩坑

    该文写于2022 1 22日 应该算是比较新的坑吧 仅供参考 转发请注明出处 该版本内置了javaFX模块 创建项目可以在左侧工具栏看到JavaFX选项 创建项目后 intelliJ自动创建的项目结构如下图 打开Main文件 发现一大堆红色
  • iOS: HTTPS 与自签名证书

    不是每个公司都会以数百美金一年的代价向CA购买SSL证书 在企业应用中 付费的SSL证书经常被自签名证书所替代 当然 对于自签名证书iOS是没有能力验证的 Safari遇到这种无法验证的自签名证书的唯一处理方法 就是将问题扔给用户 让用户决
  • zSetOperations=redisTemplate.opsForZSet();redis的Zset数据类型方法大全(zSetOperations常用方法详细)

    zSetOperations redisTemplate opsForZSet 以下是 zSetOperations 接口中定义的所有方法及其详细说明 void add K key V value double score 将一个成员添加到
  • JDBC(The end)—— 数据库连接池示例 (与线程池梦幻联动)

    写在之前 不管以后对于那种类型的池 都需要List接口利用多态的写法来对一系列集合框架类进行实例化对象 以此该对象调用add方法 来装多个此种类型的实例化对象 数据库连接池的设计思路比线程池简单易懂 以下是示例 和之前线程池的设计思想相同之
  • python怎么搭建免费代理IP池

    搭建免费代理 IP 池需要经过以下步骤 1 抓取免费代理 IP 可以通过爬虫抓取免费的代理 IP 例如可以使用 requests 和 BeautifulSoup 库实现 需要注意的是 免费代理 IP 的可用性通常比较低 需要考虑测试代理 I
  • 计算机网络学习笔记--基带(base)信号

    基带 base 保持数据波的原样进行传输称为基带传输或者基带数字信号传输 宽带 broad 在数据通信领域则指数据传输速率超过1Mps的传输系统 宽带信号则是将基带信号进行调制后形成的频分复用模拟信号 基带信号进行调制后 其频谱搬移到较高的
  • Linux更改SSH端口,并解决SSHD服务重启失败的问题

    环境 Linux Centos 7 1 进入sshd配置文件 vi etc ssh sshd config 2 找到 Port 22 这行 删掉注释符 将端口改为 想要变成的端口号 如 2022 3 重启sshd服务 systemctl r
  • 微信小程序后台销毁时间 演变和总结(热启动时间限制)

    小程序启动 这样 小程序启动可以分为两种情况 一种是冷启动 一种是热启动 冷启动 如果用户首次打开 或小程序销毁后被用户再次打开 此时小程序需要重新加载启动 即冷启动 热启动 如果用户已经打开过某小程序 然后在一定时间内再次打开该小程序 此
  • Java实现微信登录

    Java实现微信登录 代码实现微信授权 简单来说 微信授权分为四步 1 授权登录接口 生成一个二维码在页面中 2 用户点击授权成功后自动获取code 3 浏览器自动利用code访问回调接口 4 在回调接口中利用code登录 appId ap