企业微信自建应用单点登陆到第三方系统

最近在做一个项目时,接到一个需求。需要在企业微信中自建应用实现免密登陆到第三方应用,在网上查阅资料一番后,便开始实现,下面是我的大致流程,因是第一次做,所有不免有不准确的地方,还请大家多多指正。

第一步、企业微信自建应用,获取企ID(corpId),AgentId(agentId),Serect(coprsecret)

1.需要以管理员身份登录企业微信管理端后台

链接:企业微信

2.查看企业ID

这个相当于企业微信的唯一识别号,每个企业都有一个唯一的企业ID,在我的企业-企业信息中可以查看,记录下来,后面需要用到。

3.自建应用

应用管理-应用-自建应用(最下面)

填写应用信息

应用创建完之久就可以查看AgentId,Secret

不过Secret需要下发手机端查看

第二步、后端代码实现

1.需要用到的依赖

  <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.71</version>
  </dependency>
 <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.4.16</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.14</version>
        </dependency>

        <dependency>
            <groupId>commons-httpclient</groupId>
            <artifactId>commons-httpclient</artifactId>
            <version>3.1</version>
        </dependency>

2.发送http请求工具类

import com.alibaba.fastjson.JSONObject;
import com.oz.kerui.web.weixin.model.AccessToken;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.*;
import java.net.URL;
import java.text.MessageFormat;


/**
 * @Description 微信工具使用
 * @Author whl
 * @Date 2023/12/17 16:20
 **/
@Slf4j
public class WeChatUtil {
	/**
	 * 微信的请求url 获取access_token的接口地址(GET) 限200(次/天)
	 */
	public final static String access_token_url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={0}&corpsecret={1}";

    /**
     * 1.发起https请求并获取结果
     *
     * @param requestUrl    请求地址
     * @param requestMethod 请求方式(GET、POST)
     * @param outputStr     提交的数据
     * @return JSONObject(通过JSONObject.get ( key)的方式获取json对象的属性值)
     */
    public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
        JSONObject jsonObject = null;
        StringBuffer buffer = new StringBuffer();
        try {
            // 创建SSLContext对象,并使用我们指定的信任管理器初始化
            TrustManager[] tm = {new MyX509TrustManager()};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();
            URL url = new URL(requestUrl);
            HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
            httpUrlConn.setSSLSocketFactory(ssf);
            httpUrlConn.setDoOutput(true);
            httpUrlConn.setDoInput(true);
            httpUrlConn.setUseCaches(false);
            // 设置请求方式(GET/POST)
            httpUrlConn.setRequestMethod(requestMethod);
            if ("GET".equalsIgnoreCase(requestMethod)) {
                httpUrlConn.connect();
            }
            // 当有数据需要提交时
            if (null != outputStr) {
                OutputStream outputStream = httpUrlConn.getOutputStream();
                // 注意编码格式,防止中文乱码
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }
            // 将返回的输入流转换成字符串
            InputStream inputStream = httpUrlConn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            bufferedReader.close();
            inputStreamReader.close();
            // 释放资源
            inputStream.close();
            httpUrlConn.disconnect();
            jsonObject = JSONObject.parseObject(buffer.toString());
            return jsonObject;
        } catch (Exception e) {
            log.error("异常信息", e);
            return null;
        }
    }

    /**
     * 微信用户登录,登录成功后,返回相应的token 值
     *
     * @param appid     机构id
     * @param appsecret 密码
     * @return 微信用户登录,登录成功后,返回相应的token 值
     */
    public static AccessToken getAccessToken(String appid, String appsecret) {
		AccessToken accessToken = null;
		String requestUrl = MessageFormat.format(access_token_url, appid, appsecret);
		JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
        // 如果请求成功
        if (null != jsonObject) {
            try {
                accessToken = new AccessToken();
                accessToken.setToken(jsonObject.getString("access_token"));
                accessToken.setExpiresIn(jsonObject.getInteger("expires_in"));
            } catch (Exception e) {
                accessToken = null;
                // 获取token失败
                log.error("获取token失败 errcode:{} errmsg:{}",
                        jsonObject.getInteger("errcode"), jsonObject.getString("errmsg"));
                return accessToken;
            }
        }
        return accessToken;
    }



    /**
     * 向指定 URL 发送POST方法的请求
     *
     * @param url
     * 发送请求的 URL
     * @param jsonData
     * 请求参数,请求参数应该是Json格式字符串的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendJsonPost(String url, String jsonData) {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            HttpClient client = new HttpClient(); // 客户端实例化
            PostMethod postMethod = new PostMethod(url); // 请求方法post,可以将请求路径传入构造参数中

            postMethod.addRequestHeader("Content-type", "application/json; charset=utf-8");
            byte[] requestBytes = jsonData.getBytes("utf-8"); // 将参数转为二进制流

            InputStream inputStream = new ByteArrayInputStream(requestBytes, 0,requestBytes.length);
            // 请求体
            RequestEntity requestEntity = new InputStreamRequestEntity(inputStream,requestBytes.length, "application/json; charset=utf-8");
            postMethod.setRequestEntity(requestEntity); // 将参数放入请求体
            int i = client.executeMethod(postMethod); // 执行方法
            System.out.println("请求状态"+i);

            // 这里因该有判断的,根据请求状态判断请求是否成功,然后根据第三方接口返回的数据格式,解析出我们需要的数据
            byte[] responseBody = postMethod.getResponseBody(); // 得到相应数据
            String s = new String(responseBody);
            System.out.println(s);
        } catch (Exception e) {
            System.out.println("发送 POST 请求出现异常!" + e);
            e.printStackTrace();
        }
        // 使用finally块来关闭输出流、输入流
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result;
    }

}

 HttpUtil

import cn.hutool.core.map.MapUtil;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.entity.StringEntity;
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.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * http请求工具类
 *
 * @author wangfenglei
 */
public class HttpUtil {
	private static Logger log = LoggerFactory.getLogger(HttpUtil.class);
	private static PoolingHttpClientConnectionManager connectionManager = null;
	private static HttpClientBuilder httpBuilder = null;
	private static RequestConfig requestConfig = null;

	/**
	 * 最大连接连接数量
	 */
	private static int MAX_CONNECTION = 100;
	/**
	 * 最大并发请求数量
	 */
	private static int DEFAULT_MAX_CONNECTION = 50;

	static {
		// 设置http的状态参数
		requestConfig = RequestConfig.custom().setSocketTimeout(10000).setConnectTimeout(10000)
				.setConnectionRequestTimeout(10000).build();

		connectionManager = new PoolingHttpClientConnectionManager();
		connectionManager.setMaxTotal(MAX_CONNECTION);
		connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_CONNECTION);
		httpBuilder = HttpClients.custom();
		httpBuilder.setConnectionManager(connectionManager);
	}

	/**
	 * 获取http客户端连接
	 *
	 * @return http客户端连接
	 */
	public static CloseableHttpClient getConnection() {
		return httpBuilder.build();
	}

	/**
	 * http post请求,利用http请求池
	 *
	 * @param url       请求url
	 * @param paramsMap 请求参数
	 * @return 请求结果
	 * @throws Exception 异常
	 */
	public static String httpPost(String url, Map<String, String> paramsMap) throws Exception {
		List<NameValuePair> params = new ArrayList<>();

		for (Map.Entry<String, String> e : paramsMap.entrySet()) {
			NameValuePair pair = new BasicNameValuePair(e.getKey(), e.getValue());
			params.add(pair);
		}

		HttpUriRequest postMethod = RequestBuilder.post().setUri(url)
				.addParameters(params.toArray(new BasicNameValuePair[params.size()])).setConfig(requestConfig).build();

		HttpResponse response = getConnection().execute(postMethod);

		return EntityUtils.toString(response.getEntity());
	}

	/**
	 * http post请求,利用http请求池
	 *
	 * @param url       请求url
	 * @param paramsMap 请求参数
	 * @param urlParams url请求参数
	 * @return 请求结果
	 * @throws Exception 异常
	 */
	public static String httpPost(String url, Map<String, String> paramsMap, Map<String, Object> urlParams) throws Exception {
		List<NameValuePair> params = new ArrayList<>();

		for (Map.Entry<String, String> e : paramsMap.entrySet()) {
			NameValuePair pair = new BasicNameValuePair(e.getKey(), e.getValue());
			params.add(pair);
		}
		StringBuilder sb = new StringBuilder("?");
		for (Map.Entry<String, Object> e : urlParams.entrySet()) {
			sb.append(e.getKey()).append("=").append(e.getValue()).append("&");
		}
		if (urlParams!= null&&urlParams.size()!=0){
			url = url + sb.toString();
		}
		HttpUriRequest postMethod = RequestBuilder.post().setUri(url)
				.addParameters(params.toArray(new BasicNameValuePair[params.size()])).setConfig(requestConfig).build();

		HttpResponse response = getConnection().execute(postMethod);

		return EntityUtils.toString(response.getEntity());
	}

	/**
	 * http post请求,利用http请求池
	 *
	 * @param url     请求url
	 * @param jsonStr json字符串
	 * @return 请求结果
	 * @throws Exception 异常
	 */
	public static String httpPostJson(String url, String jsonStr) throws Exception {

		HttpUriRequest postMethod = RequestBuilder.post().setUri(url)
				.setHeader("Content-Type", "application/json;charset=utf-8").setHeader("Accept", "application/json")
				.setEntity(new StringEntity(jsonStr, Charset.forName("UTF-8"))).setConfig(requestConfig).build();
		HttpResponse response = getConnection().execute(postMethod);

		return EntityUtils.toString(response.getEntity());
	}

	/**
	 * http post请求,利用http请求池,设置head内容
	 *
	 * @param url     请求url
	 * @param jsonStr json字符串
	 * @param head    head内容
	 * @return 请求结果
	 * @throws Exception 异常
	 */
	public static String httpPostJson(String url, String jsonStr, Map<String, String> head) throws Exception {
		if (MapUtil.isNotEmpty(head)) {
			RequestBuilder requestBuilder = RequestBuilder.post().setUri(url)
					.setHeader("Content-Type", "application/json;charset=utf-8")
					.setHeader("Accept", "application/json");

			for (Map.Entry<String, String> entry : head.entrySet()) {
				requestBuilder.setHeader(entry.getKey(), entry.getValue());
			}

			HttpUriRequest postMethod = requestBuilder.setEntity(new StringEntity(jsonStr, Charset.forName("UTF-8")))
					.setConfig(requestConfig).build();

			HttpResponse response = getConnection().execute(postMethod);

			return EntityUtils.toString(response.getEntity());
		} else {
			return httpPostJson(url, jsonStr);
		}

	}
	
	/**
	 * http post请求,利用http请求池,设置head内容
	 *
	 * @param url     请求url
	 * @param jsonStr json字符串
	 * @param head    head内容
	 * @return 请求结果
	 * @throws Exception 异常
	 */
	public static String httpPostJson(String url, String jsonStr, Map<String, String> head,  Map<String, Object> urlParams) throws Exception {
		if (MapUtil.isNotEmpty(head)) {
			
			StringBuilder sb = new StringBuilder("?");
			for (Map.Entry<String, Object> e : urlParams.entrySet()) {
				sb.append(e.getKey()).append("=").append(e.getValue()).append("&");
			}
			if (urlParams!= null&&urlParams.size()!=0){
				url = url + sb.toString();
			}
			RequestBuilder requestBuilder = RequestBuilder.post().setUri(url)
					.setHeader("Content-Type", "application/json;charset=utf-8")
					.setHeader("Accept", "application/json");
			for (Map.Entry<String, String> entry : head.entrySet()) {
				requestBuilder.setHeader(entry.getKey(), entry.getValue());
			}

			HttpUriRequest postMethod = requestBuilder.setEntity(new StringEntity(jsonStr, Charset.forName("UTF-8")))
					.setConfig(requestConfig).build();

			HttpResponse response = getConnection().execute(postMethod);

			return EntityUtils.toString(response.getEntity());
		} else {
			return httpPostJson(url, jsonStr);
		}

	}

	/**
	 * http get请求,利用http请求池
	 *
	 * @param url 请求url
	 * @return 请求结果
	 * @throws Exception 异常
	 */
	public static String httpGet(String url) throws Exception {
		HttpUriRequest getMethod = RequestBuilder.get().setUri(url).setConfig(requestConfig).build();

		HttpResponse response = getConnection().execute(getMethod);

		return EntityUtils.toString(response.getEntity());
	}

	/**
	 * http get请求,利用http请求池
	 *
	 * @param url       请求url
	 * @param paramsMap 请求参数
	 * @return 请求结果
	 * @throws Exception 异常
	 */
	public static String httpGet(String url, Map<String, String> paramsMap) throws Exception {
		List<NameValuePair> params = new ArrayList<>();

		for (Map.Entry<String, String> e : paramsMap.entrySet()) {
			NameValuePair pair = new BasicNameValuePair(e.getKey(), e.getValue());
			params.add(pair);
		}

		HttpUriRequest getMethod = RequestBuilder.get().setUri(url)
				.addParameters(params.toArray(new BasicNameValuePair[params.size()])).setConfig(requestConfig).build();

		HttpResponse response = getConnection().execute(getMethod);

		return EntityUtils.toString(response.getEntity());
	}

	/**
	 * http get请求,利用http请求池 设置head内容
	 *
	 * @param url       请求url
	 * @param paramsMap 请求参数
	 * @param head      head内容
	 * @return 请求结果
	 * @throws Exception 异常
	 */
	public static String httpGet(String url, Map<String, String> paramsMap, Map<String, String> head) throws Exception {
		List<NameValuePair> params = new ArrayList<>();

		for (Map.Entry<String, String> e : paramsMap.entrySet()) {
			NameValuePair pair = new BasicNameValuePair(e.getKey(), e.getValue());
			params.add(pair);
		}
		RequestBuilder requestBuilder = RequestBuilder.get().setUri(url);
		for (Map.Entry<String, String> entry : head.entrySet()) {
			requestBuilder.setHeader(entry.getKey(), entry.getValue());
		}
		HttpUriRequest getMethod = requestBuilder.addParameters(params.toArray(new BasicNameValuePair[params.size()]))
				.setConfig(requestConfig).build();

		HttpResponse response = getConnection().execute(getMethod);

		return EntityUtils.toString(response.getEntity());
	}

	/**
	 * http post 请求,每次创建请求客户端
	 *
	 * @param url    url
	 * @param params 请求参数
	 * @return 请求返回值
	 */
	public static String httpPostNoPool(String url, Map<String, String> params) {
		CloseableHttpClient closeableHttpClient = null;
		try {
			HttpPost httpPost = new HttpPost(url);

			if (params != null) {
				List<NameValuePair> form = new ArrayList<>();

				for (String name : params.keySet()) {
					form.add(new BasicNameValuePair(name, params.get(name)));
				}

				httpPost.setEntity(new UrlEncodedFormEntity(form, HTTP.UTF_8));
			}

			closeableHttpClient = HttpClients.createDefault();
			CloseableHttpResponse httpResponse = closeableHttpClient.execute(httpPost);
			HttpEntity entry = httpResponse.getEntity();
			return EntityUtils.toString(entry);
		} catch (Exception e) {
			log.error("HttpUtil.httpPost failed!", e);
		} finally {
			if (null != closeableHttpClient) {
				try {
					closeableHttpClient.close();
				} catch (IOException e) {
					log.error("closeableHttpClient.close failed!", e);
				}
			}
		}

		return null;
	}

3.Controller层代码


@RestController
@RequestMapping("/dd")
public class DdLoginController {


    @Autowired
    private DdLoginService ddLoginService;

    /**
     * 单点登陆
     * @param code
     * @param
     * @return
     */
    @GetMapping("/loginPortal")
    public AjaxResult DdLogin( String code) throws Exception {
        return ddLoginService.loginPortal(code);
    }

}

4.逻辑层代码

实现单点登录,需要用前端传递过来的code获取用户信息。http请求的详细信息如下:

获取用户登陆身份

调用这个接口可以获取如下信息:

不过在发起请求之前,需要先获取当前登录企业微信用户的access_token,这个方法在工具类有。如果想进一步获取用户的敏感信息,比如性别、头像、员工个人二维码、手机、邮箱、企业邮箱、地址等,可以调用这个接口获取。

获取访问用户敏感信息

拿到用户信息后,可以用户换取第三方系统的token信息,然后返回给前端,就可以实现在企业微信自建应用里免密登录到第三方系统。以下是我的代码实现:

  /**
     * 单点登陆
     *
     * @param code
     * @return
     */
    @Override
    public AjaxResult loginPortal(String code) throws Exception {
        Map map = new HashMap();
        //获取当前登录企业微信用户token
        String token = getWeiXinToken();
        //根据code获取用户信息,url地址拼接参照官网地址
        // https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token=ACCESS_TOKEN&code=CODE
        String url = "https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token=" + token + "&code=" + code;
        JSONObject get = WeChatUtil.httpRequest(url, "GET", null);
        //获取当前登录用户的信息
        String userId = null;
        if (get.getString("errmsg").equals("ok")) {
            userId = get.getString("userid");
        }
        //获取用户详细信息
        //https://qyapi.weixin.qq.com/cgi-bin/auth/getuserdetail?access_token=ACCESS_TOKEN
        String userTicket = null;
        if (get.getString("errmsg").equals("ok")) {
            userTicket = get.getString("user_ticket");
        }
        String userInfoUrl = "https://qyapi.weixin.qq.com/cgi-bin/auth/getuserdetail?access_token=" + token;
        Map<String,String> param=new HashMap<>();
        param.put("user_ticket",userTicket);
        String json = HttpUtil.httpPostJson(userInfoUrl, null, param);
        JSONObject jsonObject = JSON.parseObject(json);

        map.put("username", userId);
        String token1 = JWTUtil.createToken(userId);
        map.put("token", token1);
        return AjaxResult.success(map);

    }

    public String getWeiXinToken() {
        return WeChatUtil.getAccessToken(corpId, coprsecret).getToken();
    }

    /**
     * 解析url字符串获取user_ticket
     *
     * @return
     */
    private String getUserTicket(String json) {
        JSONObject err = JSON.parseObject(json);
        if (err.getString("errmsg").equals("ok")) {
            return err.getString("user_ticket");
        }
        return null;
    }

    /**
     * 解析url字符串获取userid
     *
     * @param url
     * @return
     */
    private String getUserIdByCodeUrl(String url) {
        JSONObject err = JSON.parseObject(url);
        if (err.getString("errmsg").equals("ok")) {
            return err.getString("userid");
        }
        return null;
    }

第三步、自建应用配置可信IP,可信域名,应用主页

1.配置应用主页

配置工作台主页,目的就是但企业微信用户在移动端或是网页端点击自建应用,自建应用将会跳转的目标网页链接地址,可以配置网页网址获是关联小程序,这样当你点击自建应用就可以实现跳转到第三方网页链接。

2.配置可信可信域名

就是客户公司的域名,不过在开始阶段可以先配置成自己公司的域名,这个可以向项目经理要。

3.配置可信ip

客户公司的服务器ip

总结:

最后简单小节一下,要实现自建应用单点登录到第三方系统,需要获取corpId,coprsecret,agentId,发请求需要用到。然后拿前端传递过来的code去换取企业微信用户信息,再拿用户信息去换取第三方系统token信息,因为token里面包含了用户的一些基本信息,这样就可以实现免密登录到第三方系统了。

  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
【资源介绍】 基于ASP.NET+React+Mysql实现的单点登录系统源码(前端+后端)+详细说明文档.zip 技术方案 后端框架:.NET Core3.1(后期会推出 .NET 5版本) 前端框架:React 数据库:mysql(可根据实际情况,自由切换) 中间件:redis 详细功能 认证授权服务 基于IdentityServer4实现的协议,支持网站、本地应用、移动端、web服务等应用的认证授权逻辑。 单点登录登出 支持各种类型应用上的单点登录登出。开箱即用的基础用户管理模块,包括:注册、登录、手机验证码、忘记密码等。为了安全考虑,集成了腾讯图形验证码。 第三方登录(微信、钉钉) 完善的第三方登录支持。支持首次登录时绑定已存在用户或注册新用户后,自动绑定。 如何快速使用 ## 1.下载代码 csdn下载源代码到本地。根目录结构如下: 【备注】 该项目是个人毕设/课设/大作业项目,代码都经过严格调试测试,功能ok才上传,可快速上手运行!欢迎下载使用,若遇到问题请及时私信沟通,帮助解决。 该资源主要针对计算机、通信、人工智能、自动化等相关专业的学生、老师或从业者下载使用,可直接作为期末课程设计、课程大作业、毕业设计等。 项目整体具有较高的学习借鉴价值!基础还可以,动手能力强的也可做二次开发,以实现不同的功能。 欢迎下载使用,也欢迎交流学习!
企业微信应用开发是指在企业微信平台上开发自己的应用程序,以满足企业内部的特定需求或提供特定的服务。下面是企业微信应用开发的一般步骤: 1. 注册企业微信开发者账号:首先需要在企业微信官方网站上注册一个开发者账号,并获取相应的开发者权限。 2. 创应用:在企业微信管理后台创应用,填写应用基本信息,如应用名称、Logo、应用可见范围等。 3. 开发应用功能:根据需要,在企业微信开发文档中了解开发接口和功能,并进行相应的开发工作。可以通过使用企业微信提供的API,实现消息推送、成员管理、审批流程等功能。 4. 配置权限和回调URL:根据应用的功能需求,配置相应的权限和回调URL。权限设置决定了应用能够访问和操作的范围,回调URL用于接收企业微信平台的事件通知。 5. 测试与发布:在开发完成后,进行本地测试,确保应用功能正常。然后将应用提交给企业微信进行审核,并在审核通过后发布到企业微信管理后台。 6. 安装与使用:安装自应用企业微信中,然后企业成员可以在企业微信中使用该应用。 需要注意的是,企业微信开发涉及到一些安全和权限的问题,开发者需要严格按照企业微信的开发规范和安全要求进行开发,确保应用的安全性和可用性。此外,开发者还可以参考企业微信提供的开发文档和示例代码进行开发工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值