ruoyi的springboot企业微信登录方式实现(企业内部应用开发)


前言

主要是讲ruoyi前后端分离框架,springboot的微信小程序的实现方式,之前我发过一篇微信小程序的登录方式,企业微信的登录实现方式也是类似的(企业内部应用开发
在这里插入图片描述


一、企业微信的登录接口

根据企业微信开放文档企业,企业微信通过扫码后可以获得用户的code,可用于当前企业下现有的企业微信用户,并且授予基本信息

1.主要调用的企业微信api

获取用户登录身份
请求方式:GET(HTTPS)
请求地址:https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token=ACCESS_TOKEN&code=CODE
参数说明:

属性类型必填说明
access_tokenstring调用接口凭证
codestring通过成员授权获取到的code,最大为512字节。每次成员授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。前端给予的入参

2.获取企业微信的corpId

打开企业微信,点击自己头像(需要管理员权限),点击管理企业
在这里插入图片描述
点击【我的企业】,最下面有一个企业ID,就是corpId

3.建立企业应用

继续停留在管理企业页面,点击【应用管理】,最底下有一个创建应用
在这里插入图片描述
创建好了,里面会有AgentIdSecret,把它获取到,到时候要存到数据库里面.

4.配置回调域名和可信IP(*重点)

配置回调域名和可信IP,这是企业微信官方要求的,如果你的企业已经认证了并且主体跟你的服务器域名不相同就没法配置,解决方法我这里就不详细写了,一般是没有这个情况(巨坑)

点击刚才创建的应用里面,拉到最下面
在这里插入图片描述
设置可信域名(redirect_uri回调uri,数据库需要存储)和授权登录(填写你服务器域名就好)
可信IP填写你服务器的IP
注意:设置可信域名需要在你的服务器文件夹放置官方给你的文件,用于校验的

二、企业微信用户数据库设计

1.企业表

CREATE TABLE `sys_enterprise` (
  `enterprise_id` bigint NOT NULL AUTO_INCREMENT COMMENT '企业ID',
  `enterprise_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '企业名称',
  `corpid` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '企业唯一corpid',
  `agentid` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '企业应用ID',
  `corpsecret` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '企业应用秘钥',
  `redirect_uri` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT '回调URL',
  `del_flag` char(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '0' COMMENT '删除标志',
  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '创建者',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '更新者',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`enterprise_id`),
  UNIQUE KEY `uidx_corpid` (`corpid`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='企业微信表';

2.企业用户表

CREATE TABLE `sys_user_enterprise` (
  `user_id` bigint NOT NULL COMMENT '用户ID,关联sys_user的id',
  `enterprise_id` bigint NOT NULL COMMENT '企业ID,关联sys_enterprise的id',
  `enterprise_corp_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '企业微信的企业ID',
  `enterprise_name` varchar(50) COLLATE utf8mb4_bin NOT NULL COMMENT '企业名称',
  `enterprise_user_id` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT '企业微信用户ID(字符串)',
  `enterprise_nickname` varchar(50) COLLATE utf8mb4_bin NOT NULL COMMENT '企业微信用户昵称',
  `enterprise_dept_id` bigint DEFAULT NULL COMMENT '企业微信部门ID',
  `enterprise_dept_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '企业微信部门名称',
  PRIMARY KEY (`user_id`,`enterprise_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='用户企业微信表';

数据库设计尽量照着ruoyi的格式来,然后一些基本信息看自己需求来。


三、springboot登录接口实现

1.新建实体SysUserEnterprise

common模块下新建一个SysUserEnterprise,和SysUser同级

package com.ruoyi.common.core.domain.entity;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import com.ruoyi.common.core.domain.BaseEntity;


package com.echain.common.core.domain.entity;

import com.echain.common.annotation.Excel;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

/**
 * 用户企业微信对象 sys_user_enterprise
 * 
 */
@Data
public class SysUserEnterprise
{
    private static final long serialVersionUID = 1L;

    /** 用户ID */
    private Long userId;

    /** 企业ID */
    private Long enterpriseId;
    /** 企业微信用户ID */
    @Excel(name = "企业微信用户ID")
    private String enterpriseUserId;
    /** 企业微信企业ID */
    @Excel(name = "企业微信企业ID")
    private String enterpriseCorpId;
    /** 企业微信企业名称 */
    @Excel(name = "企业微信企业名称")
    private String enterpriseName;

    /** 企业微信用户昵称 */
    @Excel(name = "企业微信用户昵称")
    private String enterpriseNickname;

    /** 企业微信部门ID */
    @Excel(name = "企业微信部门ID")
    private Long enterpriseDeptId;

    /** 企业微信部门名称 */
    @Excel(name = "企业微信部门名称")
    private String enterpriseDeptName;

    public void setUserId(Long userId) 
    {
        this.userId = userId;
    }

    public Long getUserId() 
    {
        return userId;
    }
    public void setEnterpriseId(Long enterpriseId) 
    {
        this.enterpriseId = enterpriseId;
    }

    public Long getEnterpriseId() 
    {
        return enterpriseId;
    }
    public void setEnterpriseNickname(String enterpriseNickname) 
    {
        this.enterpriseNickname = enterpriseNickname;
    }

    public String getEnterpriseNickname() 
    {
        return enterpriseNickname;
    }
    public void setEnterpriseDeptId(Long enterpriseDeptId) 
    {
        this.enterpriseDeptId = enterpriseDeptId;
    }

    public Long getEnterpriseDeptId() 
    {
        return enterpriseDeptId;
    }
    public void setEnterpriseDeptName(String enterpriseDeptName) 
    {
        this.enterpriseDeptName = enterpriseDeptName;
    }

    public String getEnterpriseDeptName() 
    {
        return enterpriseDeptName;
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
            .append("userId", getUserId())
            .append("enterpriseId", getEnterpriseId())
            .append("enterpriseUserId", getEnterpriseUserId())
            .append("enterpriseNickname", getEnterpriseNickname())
            .append("enterpriseDeptId", getEnterpriseDeptId())
            .append("enterpriseDeptName", getEnterpriseDeptName())
            .toString();
    }
}

2.修改LoginUser类

在com.echain.common.core.domain.model.LoginUser的类加一个SysUserEnterprise,生成gettersetter(用了lombok可不加),并且重写LoginUser构造函数

/**             
    /**
     * 企业微信用户信息
     */
    private SysUserEnterprise userEnterprise;
    
    public LoginUser(SysUserEnterprise userEnterprise) {
        this.userEnterprise = userEnterprise;
    }

3.重写SysLoginService的login方法

这个接口是为了走SpringSecurity的登录验证方式,跟ruoyi原来的类似,并且这个是有绑定原sys_user表的数据,可以走原用户角色权限

    public String login(SysUser user, SysUserEnterprise userEnterprise, String userid, String corpsecret) {
        LoginUser loginUser = new LoginUser(userEnterprise);
        loginUser.setUserId(user.getUserId());
        loginUser.setDeptId(user.getDeptId());
        loginUser.setUser(user);
        loginUser.setPermissions(permissionService.getMenuPermission(user));
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userid, corpsecret);
        authenticationToken.setDetails(loginUser);
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        recordLoginInfo(loginUser.getUserId());
        // 生成token
        return tokenService.createToken(loginUser);
    }

4.企业微信登录接口

先添加一个企业微信接口调用凭证接口

    public String getEnterpriseAccessToken(String corpid, String corpsecret) {
        Map<String,Object> params = new HashMap<>(2);
        params.put("corpid",corpid);
        params.put("corpsecret",corpsecret);
        String accessToken = redisCache.getCacheObject("wxEnterprise" + "-" + params.get("corpid"));
        if (Objects.isNull(accessToken)) {
            accessToken = HttpUtil.get("https://qyapi.weixin.qq.com/cgi-bin/gettoken", params, 7200);
            redisCache.setCacheObject("wxEnterprise" + "-" + params.get("corpid"), accessToken, 2, TimeUnit.HOURS);
        }
        // 如果accessToken不正确再获取一次
        if (!isAccessTokenValid(accessToken)){
            redisCache.deleteObject("wxEnterprise" + "-" + params.get("corpid"));
            accessToken = HttpUtil.get("https://qyapi.weixin.qq.com/cgi-bin/gettoken", params, 7200);
            redisCache.setCacheObject("wxEnterprise" + "-" + params.get("corpid"), accessToken, 2, TimeUnit.HOURS);
        }
        return accessToken;
    }

	public boolean isAccessTokenValid(String accessToken) {
        JSONObject jsonObjects = JSONObject.parseObject(accessToken);
        Integer errcodes = (Integer) jsonObjects.get("errcode");
        // 如果错误码为0,则表示 access_token 有效;否则,表示无效
        return errcodes == 0;
    }

这里是用了redis缓存,其中corpidcorpsecret是前面说的入参,accessToken的有效期是两小时,但是不知道为什么官方的会失效,所以会判断是否有效无效就重新调一次。

然后写springboot的登录接口

    /**
     * 企业微信登录
     */
    @GetMapping(value = "/enterpriseLogin")
    @ResponseBody
    @Transactional
    public AjaxResult login(@RequestParam("code") String code, @RequestParam("corpid") String corpid) {
        AjaxResult ajax = AjaxResult.success();
        try {
            // 查找是否还存在这个企业
            SysEnterprise enterprise = enterpriseServiceImpl.selectSysEnterpriseByCorpid(corpid);
            if (Objects.isNull(enterprise)){
                return AjaxResult.error("该企业不存在");
            }
            String accessToken = loginService.getEnterpriseAccessToken(corpid, enterprise.getCorpsecret());
            JSONObject jsonObjects = JSONObject.parseObject(accessToken);
            Integer errcodes = (Integer) jsonObjects.get("errcode");
            if (errcodes == 0) {
                Map<String, Object> param = new HashMap<>(2);
                param.put("access_token", jsonObjects.getString("access_token"));
                param.put("code", code);
                String result = HttpUtil.get("https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo", param, 7200);
                JSONObject jsonObject = JSON.parseObject(result);
                Integer errcode = (Integer) jsonObject.get("errcode");
                if (errcode == 0) {
                    String userId = (String) jsonObject.get("userid");
                    QueryWrapper<SysUserEnterprise> userEnterpriseQueryWrapper = new QueryWrapper<>();
                    userEnterpriseQueryWrapper.eq("enterprise_user_id", userId);
                    userEnterpriseQueryWrapper.eq("enterprise_corp_id", corpid);
                    SysUserEnterprise userEnterprise = userEnterpriseServiceImpl.getOne(userEnterpriseQueryWrapper);
                    if (Objects.nonNull(userEnterprise)){
                        // 先查找用戶数据
                        SysUser user = userService.selectUserById(userEnterprise.getUserId());
                        // 生成令牌
                        String token = loginService.login(user, userEnterprise, userId, enterprise.getCorpsecret());
                        ajax.put(Constants.TOKEN, token);
                        return ajax;
                    }
                }
            }
            // 请求重定向
        } catch (Exception e) {
            throw new ServiceException(e.getMessage());
        }
        return AjaxResult.error("登录失败");
    }

selectSysEnterpriseByCorpid方法这个自己写一下吧,实际就是数据库查sys_enterprise表是否存在这行数据.
到这里就大功告成了,存数据库这个操作我就不详细说了,还有要注意如果没有引入mybatis-plusQueryWrapper那边需要改成根据enterprise_user_id和enterprise_corp_id获取用户信息的方法

5.开放接口

com.echain.framework.config.SecurityConfig的configure方法放行登录接口,在前面的/login、/captchaImage接口加一个/enterpriseLogin(根据自身需求加)

// 对于登录login 验证码captchaImage 允许匿名访问
.antMatchers("/login", "/captchaImage", "/enterpriseLogin").anonymous()

总结

实现之后,就能跟以前ruoyi的登录,通过token携带来访问接口,因为绑定了SysUser用户表,所以权限实际上还是跟着原用户角色权限走了,非常方便;如果遇到无法设置回调域名问题,可以评论区提问,一般是说跟企业主体不一致导致的。

参考博客:ruoyi的springboot微信小程序登录实现方式(我自己写的,感兴趣的可以去看一下)

Flask是一个轻量级的Python Web框架,它可以用来构建Web应用程序。企业微信应用是一种能够在企业微信平台上运行的应用程序,可以帮助企业内部进行沟通、协作和管理。 在Flask中,我们可以使用Flask的路由机制来处理企业微信应用的回调请求。回调是指企业微信平台在某些事件发生时向企业微信应用发送HTTP请求,应用需要对这些请求进行响应。 首先,我们需要配置企业微信应用的回调URL,即将该URL与Flask应用中的某个路由函数进行绑定。当企业微信平台有回调请求时,Flask应用会自动调用与该URL绑定的路由函数。 在路由函数中,我们可以根据请求的类型和内容进行处理。例如,可以根据请求的事件类型来执行相应的操作,如发送消息、获取通讯录信息等。同时,还可以根据请求的参数来获取相应的数据,并进行相应的处理和返回。 在处理回调请求时,还需要注意验证请求的有效性。企业微信平台会通过加密算法将请求进行加密,我们需要按照约定的方式进行解密,并校验相关参数的合法性,以确保请求的安全性和有效性。 总的来说,Flask提供了便捷的路由功能,可以轻松地处理企业微信应用的回调请求。通过合理地运用Flask的路由机制,我们可以根据不同的事件和请求类型,进行相应的操作和处理,实现丰富多样的企业微信应用功能。同时,确保回调请求的有效性和安全性也是非常重要的。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值