一切都过去 發表於 2026-3-10 11:34:00

Java 实现企业微信扫码登录

<h1>一、场景</h1>
<p>Web 系统登录页面“企业微信”图标,点击后调取企业微信扫码登录页面,扫码成功后判断系统账号与企业微信用户ID绑定情况,有则直接登录,无则跳转到绑定登录页面,用户手动输入个人账号密码进行绑定,首次绑定后后续无需再绑定。</p>
<h1>二、企业微信应用相关配置</h1>
<h2>1、新建企微应用</h2>
<p>进入企微管理后台,应用管理模块,点击创建应用,填写应用名称、介绍,设置应用Logo,点击创建应用。</p>
<p><img src="https://img2024.cnblogs.com/blog/1869035/202603/1869035-20260310110659214-1872765988.png" alt="image" width="281" height="354" loading="lazy"></p>
<h2>&nbsp;2、应用 ID 和 Secret</h2>
<p>创建好应用后,保存好应用的 AgentId 和 Secret,后续系统调用企微接口会用到。</p>
<p><img src="https://img2024.cnblogs.com/blog/1869035/202603/1869035-20260310111041690-1837225963.png" alt="image" width="682" height="203" loading="lazy"></p>
<p>以及企业ID(在管理后台 - 我的企业中查看)。</p>
<p><img src="https://img2024.cnblogs.com/blog/1869035/202603/1869035-20260310110927330-548611091.png" alt="image" loading="lazy"></p>
<h2>&nbsp;3、配置可信域名、授权回调域、企业可信IP</h2>
<p>如果系统地址为 http://www.oa.com:8099,则可信域名、授权回调域填写 www.oa.com:8099。并且确保系统授权流程中的回调接口地址也是 http://www.oa.com:8099/xxx/xxx 格式,有任意一处对不上,进行扫码登录时会提示:edirect_uri 与配置的授权完成回调域名不一致 问题。</p>
<p>配置可信域名时可能会让进行域名归属认证,下载认证文件,放到域名访问根目录下,确保&nbsp;http://www.oa.com:8099/WW_verify_xxxxxxx.txt,在浏览器可访问(会显示WW_verify_xxxxxxx.txt内的内容),具体实现方式根据系统的部署方式决定,可根据系统的部署方式询问AI。</p>
<p><img src="https://img2024.cnblogs.com/blog/1869035/202603/1869035-20260310111147238-107563890.png" alt="image" width="624" height="337" loading="lazy"></p>
<h1>&nbsp;三、Java 流程实现</h1>
<p>常量参数:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 企微企业 ID</span>
String wxworkCorpId =<span style="color: rgba(0, 0, 0, 1)"> xxx;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 企微应用 AgentId</span>
String wxworkAgentId =<span style="color: rgba(0, 0, 0, 1)"> xxx;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 企微应用 Secret</span>
String wxworkSecret =<span style="color: rgba(0, 0, 0, 1)"> xxx;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 登录回调地址</span>
String wxworkRedirectUri = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">http://www.oa.com:8099/wxwork/callback</span><span style="color: rgba(128, 0, 0, 1)">"</span>;</pre>
</div>
<p>跳转到企微登录页:</p>
<div class="cnblogs_code">
<pre>    <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
   * 跳转到企业微信扫码登录页面
   </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
    @GetMapping(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/wxwork/login</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> wxworkLogin(HttpServletResponse response) throws Exception {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 企业微信网页扫码授权 URL</span>
      String authUrl = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">https://open.work.weixin.qq.com/wwopen/sso/qrConnect?</span><span style="color: rgba(128, 0, 0, 1)">"</span>
                + <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">appid=</span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> wxworkCorpId
                </span>+ <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">&amp;agentid=</span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> wxworkAgentId
                </span>+ <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">&amp;redirect_uri=</span><span style="color: rgba(128, 0, 0, 1)">"</span> + URLEncoder.encode(wxworkRedirectUri, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">UTF-8</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
                </span>+ <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">&amp;state=meiqu_erp</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
      response.sendRedirect(authUrl);
    }</span></pre>
</div>
<p>企业微信登录回调:</p>
<div class="cnblogs_code">
<pre>    @GetMapping(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/wxwork/callback</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> String wxworkCallback(@RequestParam(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">code</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">) String code,
                                  @RequestParam(value </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">state</span><span style="color: rgba(128, 0, 0, 1)">"</span>, required = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">) String state,
                                  HttpServletRequest request) throws Exception {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 1. 获取企业微信 access_token</span>
      String accessToken =<span style="color: rgba(0, 0, 0, 1)"> getWxworkAccessToken();
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 2. 用 code 换取用户的 UserId</span>
      String userId =<span style="color: rgba(0, 0, 0, 1)"> getWxworkUserId(accessToken, code);

      </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (StringUtils.isBlank(userId)) {
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">redirect:/login?error=wxwork_auth_failed</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
      }

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 3. 根据企业微信 userId 查找绑定的系统用户
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 3.1 userId 没有匹配到系统用户,跳转到绑定页面,让用户首次手动输入系统账户密码进行绑定
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 3.2 userId 匹配到系统用户,跳转登录。</span>
    }   </pre>
</div>
<p>获取企业微信 access_token:</p>
<div class="cnblogs_code">
<pre>    <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
   * 获取企业微信 access_token
   * 接口:GET </span><span style="color: rgba(0, 128, 0, 1); text-decoration: underline">https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=xxx</span><span style="color: rgba(0, 128, 0, 1)">&amp;corpsecret=xxx
   </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String getWxworkAccessToken() throws Exception {
      String url </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">https://qyapi.weixin.qq.com/cgi-bin/gettoken?</span><span style="color: rgba(128, 0, 0, 1)">"</span>
                + <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">corpid=</span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> wxworkCorpId
                </span>+ <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">&amp;corpsecret=</span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> wxworkSecret;
      String result </span>=<span style="color: rgba(0, 0, 0, 1)"> getJson(url);
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> JSON.parseObject(result).getString(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">access_token</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
    }</span></pre>
</div>
<p>用 Code 换取用户的 UserId:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
   * 用 code 换取企业微信用户的 UserId
   * 接口:GET </span><span style="color: rgba(0, 128, 0, 1); text-decoration: underline">https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=xxx</span><span style="color: rgba(0, 128, 0, 1)">&amp;code=xxx
   </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String getWxworkUserId(String accessToken, String code) throws Exception {
      String url </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?</span><span style="color: rgba(128, 0, 0, 1)">"</span>
                + <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">access_token=</span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> accessToken
                </span>+ <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">&amp;code=</span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> code;
      String result </span>=<span style="color: rgba(0, 0, 0, 1)"> getJson(url);
      JSONObject json </span>=<span style="color: rgba(0, 0, 0, 1)"> JSON.parseObject(result);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> errcode=0 表示成功,UserId 为企业内用户ID</span>
      <span style="color: rgba(0, 0, 255, 1)">if</span> (json.getIntValue(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">errcode</span><span style="color: rgba(128, 0, 0, 1)">"</span>) == <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">) {
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> json.getString(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">UserId</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
      }
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
    }</span></pre>
</div>
<p>&nbsp;</p>

</div>
<div id="MySignature" role="contentinfo">
    <div style="border: 2px solid yellow;">
<p style="font-weight:bold;">时间仓促,如有错误欢迎指出,欢迎在评论区讨论,如对您有帮助还请点个推荐、关注支持一下</p>
<p style="font-weight:bold;">作者:博客园 - 凉年技术</p>
<p style="font-weight:bold;">出处:http://www.cnblogs.com/xxhxs-21/</p>
<p>本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文链接,否则保留追究法律责任的权利。</p>
<p>若内容有侵犯您权益的地方,请公告栏处联系本人,本人定积极配合处理解决。</p>
</div><br><br>
来源:https://www.cnblogs.com/xxhxs-21/p/19695997
頁: [1]
查看完整版本: Java 实现企业微信扫码登录