Java企业微信开发_09_身份验证之移动端网页授权(有完整项目源码)

简介: 注: 源码已上传github: https://github.com/shirayner/WeiXin_QiYe_Demo   一、本节要点 1.1 授权回调域(可信域名) 在开始使用网页授权之前,需要先设置一下授权回调域。

注: 源码已上传github: https://github.com/shirayner/WeiXin_QiYe_Demo

 

一、本节要点

1.1 授权回调域(可信域名)

在开始使用网页授权之前,需要先设置一下授权回调域。这里瞬间想到之前做JSSDK的时候,也设置过一个域名。二者本质上都是设置可信域名。

当用户授权完毕之后,请求将重定向到此域名(或者子域名)下的执行者(jsp页面或者servlet等)。如何设置授权回调域,请见第二节。

 

1.2 获取Code

https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&agentid=AGENTID&state=STATE#wechat_redirect

可将根据此链接生成一个view菜单按钮,用户点击此按钮时,将跳转到授权页面,授权成功后,页面重定向到指定的REDIRECT_URI页面,同时带上code和state请求参数,即页面将跳转至 redirect_uri?code=CODE&state=STATE页面。

 

1.3 移动端网页授权流程

(1)用户点击1.2中菜单按钮,跳转至授权页面

(2)用户授权成功,页面重定向到 redirect_uri?code=CODE&state=STATE 页面

(3)接收code,根据code获取成员信息(UserId,user_ticket)

(4)拿到UserId后可选择去根据UserId获取成员详细信息, 参见Java企业微信开发_02_通讯录同步 中的 Contacts_UserService类

(5) 拿到 user_ticket后可选择去使用user_ticket获取成员详情(其中包括用户头像)

在此我们只关注于打通 企业微信官方文档中 移动端网页授权 相关的接口,这是基础,至于实际工作中企业是如何去具体实现他们自己的授权业务,暂时不在我们讨论的范围内。

 

 

二、代码实现

2.1设置可信域名(授权回调域

登录企业微信后台—>企业应用—>自建应用中的你的具体应用—>企业微信授权登录—>Web网页

 

 

 

 

 

2.2 生成菜单按钮

添加一个用于网页授权的菜单按钮,运行MenuTest.testCreateMenu()方法生成按钮。

在已经成功生成菜单按钮时,有时可能出现菜单没有及时更新的情况,这时可以通过取消关注企业号,再重新关注企业号来解决这个问题。

(1)MenuService.java

package com.ray.service;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.ray.pojo.menu.Button;
import com.ray.pojo.menu.CommonButton;
import com.ray.pojo.menu.ComplexButton;
import com.ray.pojo.menu.Menu;
import com.ray.pojo.menu.ViewButton;
import com.ray.util.WeiXinUtil;

import net.sf.json.JSONObject;


public class MenuService {
    private static Logger log = LoggerFactory.getLogger(MenuService.class);  
    // 菜单创建(POST) 限100(次/天)  
    public static String create_menu_url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN&agentid=AGENTID";  

    /** 
     * 1.创建菜单 
     *  
     * @param menu 菜单实例 
     * @param accessToken 有效的access_token 
     * @return 0表示成功,其他值表示失败 
     */  
    public void createMenu(String accessToken,Menu menu,int agentId) {  

        //1.获取json字符串:将Menu对象转换为json字符串
        Gson gson = new Gson(); 
        String jsonMenu =gson.toJson(menu);      //使用gson.toJson(user)即可将user对象顺序转成json
        System.out.println("jsonMenu:"+jsonMenu);


        //2.获取请求的url  
        create_menu_url = create_menu_url.replace("ACCESS_TOKEN", accessToken)
                .replace("AGENTID", String.valueOf(agentId));  

        //3.调用接口,发送请求,创建菜单  
        JSONObject jsonObject = WeiXinUtil.httpRequest(create_menu_url, "POST", jsonMenu);  
        System.out.println("jsonObject:"+jsonObject.toString());

        //4.错误消息处理
        if (null != jsonObject) {  
            if (0 != jsonObject.getInt("errcode")) {  
                log.error("创建菜单失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));  
            }  
        }  
 
    }  

    /** 
     * 2.组装菜单数据 
     *  
     * @return 
     */  
    public  Menu getMenu() {  
    /*    ViewButton btn11 = new ViewButton();  
        btn11.setName("添加报销单");  
        btn11.setType("view");  
        btn11.setUrl("http://5nffqn.natappfree.cc/WeiXin_QiYe_Demo/uploadExpenseAccaout.jsp");  
*/
        ViewButton btn11 = new ViewButton();  
        btn11.setName("JSSDK多图上传");  
        btn11.setType("view");  
        btn11.setUrl("http://zvuntx.natappfree.cc/WeiXin_QiYe_Demo/JSSDKUploadPics.jsp");  

        ViewButton btn21 = new ViewButton();  
        btn21.setName("JSSDK测试(全)");  
        btn21.setType("view");  
        btn21.setUrl("http://zvuntx.natappfree.cc/WeiXin_QiYe_Demo/jsapiTicktAll.jsp");  

        ViewButton btn22 = new ViewButton();  
        btn22.setName("PC端网页授权");  
        btn22.setType("view");  
        btn22.setUrl("https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=ww92f5da92bb24696e&agentid=1000002&redirect_uri=http%3A%2F%2Fzvuntx.natappfree.cc%2FWeiXin_QiYe_Demo%2FPCAuthorization.jsp&state=state");  

        ViewButton btn23 = new ViewButton();  
        btn23.setName("移动端网页授权");  
        btn23.setType("view");  
        btn23.setUrl("https://open.weixin.qq.com/connect/oauth2/authorize?appid=ww92f5da92bb24696e&redirect_uri=http%3A%2F%2Fzvuntx.natappfree.cc%2FWeiXin_QiYe_Demo%2FMTAuthorization.jsp&response_type=code&scope=snsapi_privateinfo&agentid=1000002&state=hec#wechat_redirect");  

        
        CommonButton btn12 = new CommonButton();  
        btn12.setName("扫一扫");  
        btn12.setType("click");  
        btn12.setKey("12");  

        
        
        CommonButton btn13 = new CommonButton();  
        btn13.setName("翻译功能");  
        btn13.setType("click");  
        btn13.setKey("13");  

        ViewButton btn14 = new ViewButton();  
        btn14.setName("上传图片");  
        btn14.setType("view");  
        btn14.setUrl("http://5nffqn.natappfree.cc/WeiXin_SanFenBaiXue/uploadimg.jsp");  



        ViewButton btn15 = new ViewButton();  
        btn15.setName("上传图片2");  
        btn15.setType("view");  
        btn15.setUrl("http://5nffqn.natappfree.cc/WeiXin_SanFenBaiXue/index2.jsp");  

    
    

        

        

        CommonButton btn24 = new CommonButton();  
        btn24.setName("人脸识别");  
        btn24.setType("click");  
        btn24.setKey("24");  

        CommonButton btn25 = new CommonButton();  
        btn25.setName("聊天唠嗑");  
        btn25.setType("click");  
        btn25.setKey("25");  

        CommonButton btn31 = new CommonButton();  
        btn31.setName("Q友圈");  
        btn31.setType("click");  
        btn31.setKey("31");  

        CommonButton btn33 = new CommonButton();  
        btn33.setName("幽默笑话");  
        btn33.setType("click");  
        btn33.setKey("33");  

        CommonButton btn34 = new CommonButton();  
        btn34.setName("用户反馈");  
        btn34.setType("click");  
        btn34.setKey("34");  

        CommonButton btn35 = new CommonButton();  
        btn35.setName("关于我们");  
        btn35.setType("click");  
        btn35.setKey("35");  

        ViewButton btn32 = new ViewButton();  
        btn32.setName("周边搜索");  
        btn32.setType("view");  
        btn32.setUrl("http://liufeng.gotoip2.com/xiaoqrobot/help.jsp");  

        ComplexButton mainBtn1 = new ComplexButton();  
        mainBtn1.setName("正在做功能");  
        mainBtn1.setSub_button(new Button[] { btn11, btn12, btn13, btn14, btn15 });  

        ComplexButton mainBtn2 = new ComplexButton();  
        mainBtn2.setName("测试");  
        mainBtn2.setSub_button(new Button[] { btn21, btn22, btn23, btn24, btn25 });  

        ComplexButton mainBtn3 = new ComplexButton();  
        mainBtn3.setName("更多");  
        mainBtn3.setSub_button(new Button[] { btn31, btn33, btn34, btn35, btn32 });  

        /** 
         * 这是企业号目前的菜单结构,每个一级菜单都有二级菜单项<br> 
         *  
         * 在某个一级菜单下没有二级菜单的情况,menu该如何定义呢?<br> 
         * 比如,第三个一级菜单项不是“更多体验”,而直接是“幽默笑话”,那么menu应该这样定义:<br> 
         * menu.setButton(new Button[] { mainBtn1, mainBtn2, btn33 }); 
         */  
        Menu menu = new Menu();  
        menu.setButton(new Button[] { mainBtn1, mainBtn2, mainBtn3 });  

        return menu;  
    }  

}
View Code

 

(2)MenuTest.java

package com.ray.test;

import org.junit.Test;

import com.ray.pojo.menu.Menu;
import com.ray.service.MenuService;
import com.ray.util.WeiXinParamesUtil;
import com.ray.util.WeiXinUtil;

public class MenuTest {
    
  @Test    
  public void testCreateMenu(){
      //1.组装菜单
      MenuService ms=new MenuService();
      Menu menu=ms.getMenu();
      
      //2.获取access_token:根据企业id和应用密钥获取access_token
      String accessToken=WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
      System.out.println("accessToken:"+accessToken);
      
      //3.创建菜单
      ms.createMenu( accessToken, menu, WeiXinParamesUtil.agentId);
      
     
    
  }
  
  
  
  
}
View Code

 

 2.3 移动端网页授权业务类——MTAuthorizationService.java

包括两个方法:

(1)根据code获取成员信息

(2)使用userTicket获取成员详情

package com.ray.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.ray.pojo.UserTicket;
import com.ray.util.WeiXinUtil;

import net.sf.json.JSONObject;


/**
 * @desc  : 移动端网页授权Service
 * 
 * @author: shirayner
 * @date  : 2017年9月14日 下午12:18:38
 */
public class MTAuthorizationService {
    private static Logger log = LoggerFactory.getLogger(MenuService.class);  

    public static final String GET_USERINFO_URL = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=ACCESS_TOKEN&code=CODE";  
    
    public static final String GET_USERDETAIL_URL = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserdetail?access_token=ACCESS_TOKEN";  

    /** 1.根据code获取成员信息
     * @desc :GET请求、
     * 成员信息包括
     * UserId    成员UserID
     * DeviceId    手机设备号(由企业微信在安装时随机生成,删除重装会改变,升级不受影响)
     * user_ticket    成员票据,最大为512字节。scope为snsapi_userinfo或snsapi_privateinfo,且用户在应用可见范围之内时返回此参数。
     *              后续利用该参数可以获取用户信息或敏感信息。
     * expires_in    user_token的有效时间(秒),随user_ticket一起返回
     *  
     * @param accessToken
     * @param code void
     */
    public JSONObject getUserInfo(String accessToken,String code) {
        //1.获取请求的url  
        String get_userInfo_url=GET_USERINFO_URL.replace("ACCESS_TOKEN", accessToken)
                .replace("CODE", code);

        //2.调用接口,发送请求,获取成员信息
        JSONObject jsonObject = WeiXinUtil.httpRequest(get_userInfo_url, "GET", null);  
        System.out.println("jsonObject:"+jsonObject.toString());

        //3.错误消息处理
        if (null != jsonObject) {  
            if (0 != jsonObject.getInt("errcode")) {  
                log.error("获取成员信息失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));  
            }  
        }  
        
        return jsonObject;
        
    }
    /** 2.使用userTicket获取成员详情
     * @desc :POST请求
     *  
     * @param accessToken
     * @param userTicket
     * @return JSONObject
     */
    public JSONObject getUserDetail(String accessToken,UserTicket userTicket) {
        //1.获取请求地址  
        String get_userDetail_url=GET_USERDETAIL_URL.replace("ACCESS_TOKEN", accessToken);

        //2.准备好请求包体
        Gson gson = new Gson(); 
        String jsonUserTicket =gson.toJson(userTicket);      //使用gson.toJson(user)即可将user对象顺序转成json
        System.out.println("jsonUserTicket:"+jsonUserTicket);
        
        //2.调用接口,发送请求,获取成员信息
        JSONObject jsonObject = WeiXinUtil.httpRequest(get_userDetail_url, "POST", jsonUserTicket);  
        System.out.println("jsonObject:"+jsonObject.toString());

        //3.错误消息处理
        if (null != jsonObject) {  
            if (0 != jsonObject.getInt("errcode")) {  
                log.error("获取成员信息失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));  
            }  
        }  
        
        return jsonObject;
        
    }
    
    
}
View Code

 

 2.4前端页面——MTAuthorization.jsp

 授权成功后将跳转到这个页面。在这个页面里调用了MTAuthorizationService中的方法来获取用户信息

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"     %>
    <%@page language="java" import="com.ray.pojo.*"%>
<%@page language="java" import="com.ray.service.*"%>
<%@page language="java" import="com.ray.util.*"%>
<%@page language="java" import="net.sf.json.JSONObject"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>移动端网页授权</title>

<script src="/js/jquery.js"></script>
<script src="http://rescdn.qqmail.com/node/ww/wwopenmng/js/sso/wwLogin-1.0.0.js"></script>
</head>
<body>

<%
         String code= request.getParameter("code");
         String state=request.getParameter("state");
         
         MTAuthorizationService mts=new MTAuthorizationService();
         String accessToken=WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
         //获取成员信息
         JSONObject userInfo=mts.getUserInfo(accessToken, code);
         
         //获取成员详情
         UserTicket userTicket=new UserTicket();
         userTicket.setUser_ticket(userInfo.getString("user_ticket"));

        JSONObject userDetail=mts.getUserDetail(accessToken, userTicket);
        
         
         
%>
hello,这里是第三方应用
code=<%= code%>    <br>
state=<%= state%>      <br>
userInfo=<%= userInfo.toString()%>    <br><br>
userTicket=<%= userInfo.getString("user_ticket")%>   <br><br>
userDetail=<%= userDetail.toString()%>   <br><br>

</body>
</html>
View Code

 

相关实践学习
基于函数计算快速搭建Hexo博客系统
本场景介绍如何使用阿里云函数计算服务命令行工具快速搭建一个Hexo博客。
目录
相关文章
|
7天前
|
小程序 前端开发 API
微信小程序全栈开发中的异常处理与日志记录
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的异常处理和日志记录,强调其对确保应用稳定性和用户体验的重要性。异常处理涵盖前端(网络、页面跳转、用户输入、逻辑异常)和后端(数据库、API、业务逻辑)方面;日志记录则关注关键操作和异常情况的追踪。实践中,前端可利用try-catch处理异常,后端借助日志框架记录异常,同时采用集中式日志管理工具提升分析效率。开发者应注意安全性、性能和团队协作,以优化异常处理与日志记录流程。
|
7天前
|
小程序 安全 数据安全/隐私保护
微信小程序全栈开发中的身份认证与授权机制
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的身份认证与授权机制。身份认证包括手机号验证、微信登录和第三方登录,而授权机制涉及角色权限控制、ACL和OAuth 2.0。实践中,开发者可利用微信登录获取用户信息,集成第三方登录,以及实施角色和ACL进行权限控制。注意点包括安全性、用户体验和合规性,以保障小程序的安全运行和良好体验。通过这些方法,开发者能有效掌握小程序全栈开发技术。
|
7天前
|
JavaScript 前端开发 小程序
微信小程序全栈开发之性能优化策略
【4月更文挑战第12天】本文探讨了微信小程序全栈开发的性能优化策略,包括前端的资源和渲染优化,如图片压缩、虚拟DOM、代码分割;后端的数据库和API优化,如索引创建、缓存使用、RESTful API设计;以及服务器的负载均衡和CDN加速。通过这些方法,开发者可提升小程序性能,优化用户体验,增强商业价值。
|
7天前
|
小程序 前端开发 JavaScript
微信小程序全栈开发中的PWA技术应用
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中PWA技术的应用,PWA结合Web的开放性和原生应用的性能,提供离线访问、后台运行、桌面图标和原生体验。开发者可利用Service Worker实现离线访问,Worker处理后台运行,Web App Manifest添加桌面图标,CSS和JavaScript提升原生体验。实践中需注意兼容性、性能优化和用户体验。PWA技术能提升小程序的性能和用户体验,助力开发者打造优质小程序。
|
1天前
|
前端开发 Java Go
开发语言详解(python、java、Go(Golong)。。。。)
开发语言详解(python、java、Go(Golong)。。。。)
|
1天前
|
人工智能 前端开发 Java
Java语言开发的AI智慧导诊系统源码springboot+redis 3D互联网智导诊系统源码
智慧导诊解决盲目就诊问题,减轻分诊工作压力。降低挂错号比例,优化就诊流程,有效提高线上线下医疗机构接诊效率。可通过人体画像选择症状部位,了解对应病症信息和推荐就医科室。
27 10
|
1天前
|
Java 关系型数据库 MySQL
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
UWB (ULTRA WIDE BAND, UWB) 技术是一种无线载波通讯技术,它不采用正弦载波,而是利用纳秒级的非正弦波窄脉冲传输数据,因此其所占的频谱范围很宽。一套UWB精确定位系统,最高定位精度可达10cm,具有高精度,高动态,高容量,低功耗的应用。
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
|
3天前
|
安全 Java 数据安全/隐私保护
使用Spring Security进行Java身份验证与授权
【4月更文挑战第16天】Spring Security是Java应用的安全框架,提供认证和授权解决方案。通过添加相关依赖到`pom.xml`,然后配置`SecurityConfig`,如设置用户认证信息和URL访问规则,可以实现应用的安全保护。认证流程包括请求拦截、身份验证、响应生成和访问控制。授权则涉及访问决策管理器,如基于角色的投票。Spring Security为开发者构建安全应用提供了全面且灵活的工具,涵盖OAuth2、CSRF保护等功能。
|
4天前
|
JavaScript Java 测试技术
基于Java的企业文档管理系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的企业文档管理系统的设计与实现(源码+lw+部署文档+讲解等)
16 0
|
7天前
|
SQL 安全 小程序
探索微信小程序全栈开发的安全性问题
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的安全性问题,包括数据安全、接口安全、隐私保护和代码安全。为解决这些问题,建议采取数据加密、使用HTTPS协议、身份认证与授权、输入验证、安全审计及漏洞扫描以及安全培训等措施。通过这些方法,开发者可提升小程序安全性,保护用户隐私和数据。

热门文章

最新文章