微信企业号OAuth2验证接口的使用

 以微信为入口的微信企业号第三方应用,难免需要获取用户个人信息。企业应用中的URL链接(包括自定义菜单或者消息中的链接),可以通过OAuth2.0验证接口来获取成员的身份信息。

  通过此接口获取成员身份会有一定的时间开销。对于频繁获取成员身份的场景,建议采用如下方案:
1、企业应用中的URL链接直接填写企业自己的页面地址
2、成员跳转到企业页面时,企业校验是否有代表成员身份的cookie,此cookie由企业生成
3、如果没有获取到cookie,重定向到OAuth验证链接,获取成员身份后,由企业生成代表成员身份的cookie
4、根据cookie获取成员身份,进入相应的页面
注意,此URL的域名,必须完全匹配企业应用设置项中的‘可信域名‘,否则获取成员信息时会返回50001错误码。

1,实现思路:

OAuth2验证可以使用多种方式,此处使用注解方式。设计思路是在需要获取用户信息的GET请求上添加注解,然后在调用的时候判断是否包含此注解,然后做处理流程。
每次请求包含2种情况:
1.不需要获取用户信息,直接跳转到指定视图;
2.需要获取用户信息,此处分2种情况:
a.session中存储了之前获取的用户信息,则直接跳转到指定视图;
b.session中不包含用户信息,则需要构造带回调参数的URL去微信API服务器获取code参数,然后通过code参数调用API换取Userid并保存到session,然后再次跳转到初始请求的视图页面。

2,代码

创建拦截器:OAuth2Interceptor

  1. package org.oms.qiye.interceptor;  
  2.   
  3. import java.io.UnsupportedEncodingException;  
  4. import java.lang.reflect.Method;  
  5.   
  6. import javax.servlet.http.HttpServletRequest;  
  7. import javax.servlet.http.HttpServletResponse;  
  8. import javax.servlet.http.HttpSession;  
  9.   
  10. import org.springframework.web.method.HandlerMethod;  
  11. import org.springframework.web.servlet.HandlerInterceptor;  
  12. import org.springframework.web.servlet.ModelAndView;  
  13.   
  14. public class OAuth2Interceptor implements HandlerInterceptor {  
  15.   
  16.     /** 
  17.      * 在DispatcherServlet完全处理完请求后被调用 
  18.      * 当有拦截器抛出异常时,会从当前拦截器往回执行所有的拦截器的afterCompletion() 
  19.      */  
  20.     @Override  
  21.     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {  
  22.         System.out.println("**执行顺序: 3、afterCompletion**");  
  23.   
  24.     }  
  25.   
  26.     /** 
  27.      * 在业务处理器处理请求执行完成后,生成视图之前执行的动作 
  28.      */  
  29.     @Override  
  30.     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object arg2, ModelAndView modelAndView) throws Exception {  
  31.         System.out.println("**执行顺序: 2、postHandle**");  
  32.   
  33.     }  
  34.   
  35.     /** 
  36.      * 在业务处理器处理请求之前被调用 如果返回false 从当前的拦截器往回执行所有拦截器的afterCompletion(),再退出拦截器链 
  37.      * 如果返回true 执行下一个拦截器,直到所有的拦截器都执行完毕 再执行被拦截的Controller 然后进入拦截器链, 
  38.      * 从最后一个拦截器往回执行所有的postHandle() 接着再从最后一个拦截器往回执行所有的afterCompletion() 
  39.      */  
  40.     @Override  
  41.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  
  42.         System.out.println("**执行顺序: 1、preHandle**");  
  43.         String url = request.getRequestURL().toString();  
  44.   
  45.         HttpSession session = request.getSession();  
  46.         // 先判断是否有注解  
  47.   
  48.         HandlerMethod handlerMethod = (HandlerMethod) handler;  
  49.         Method method = handlerMethod.getMethod();  
  50.         OAuthRequired annotation = method.getAnnotation(OAuthRequired.class);  
  51.         if (annotation != null) {  
  52.             System.out.println("OAuthRequired:你的访问需要获取登录信息!");  
  53.             Object objUid = session.getAttribute("UserId");  
  54.             if (objUid == null) {  
  55.                 String resultUrl = request.getRequestURL().toString();  
  56.                 String param=request.getQueryString();  
  57.                 if(param!=null){  
  58.                     resultUrl+= "?" + param;  
  59.                 }  
  60.                 System.out.println("resultUrl="+resultUrl);  
  61.                 try {  
  62.                     resultUrl = java.net.URLEncoder.encode(resultUrl, "utf-8");  
  63.                 } catch (UnsupportedEncodingException e) {  
  64.                     e.printStackTrace();  
  65.                 }  
  66.                 //请求的路径  
  67.                 String contextPath=request.getContextPath();  
  68.                 response.sendRedirect(contextPath + "/oauth2.do?resultUrl=" + resultUrl);  
  69.                 return false;  
  70.             }  
  71.   
  72.         }  
  73.         return true;  
  74.     }  
  75.   
  76. }  

验证OAuth2注解OAuthRequired

  1. package org.oms.qiye.interceptor;  
  2.   
  3. import java.lang.annotation.*;  
  4. /** 
  5.  * 验证OAuth2注解 
  6.  * @author Sunlight 
  7.  * 
  8.  */  
  9. @Retention(RetentionPolicy.RUNTIME)  
  10. @Target(ElementType.METHOD)  
  11. public @interface OAuthRequired {  
  12.       
  13. }  

常量类,此处可以替换为持久化数据读取;

  1. package org.oms.qiye.util;  
  2.   
  3. public class Constants {  
  4.     /** 
  5.      * 常量说明: 
  6.      * 此处定义的常量需要持久化,可以保存在数据库中,在需要的地方读取。 
  7.      * 在多企业号中,最好以每个应用来定义。 
  8.      */  
  9.     public static final int AGENTID = 1;  
  10.     public static final String TOKEN = "sunlight";  
  11.     public static final String CORPID = "你的企业号ID";  
  12.     public static final String Secret = "你的企业号_ACCESS_TOKEN";  
  13.     public static final String encodingAESKey = "s8vFF4f6AWay3uAdJh79WD6imaam4BV6Kl4eL4UzgfM";  
  14. }  

OAuth2 处理控制器OAuth2Controller

  1. package org.oms.qiye.web;  
  2.   
  3. import java.io.UnsupportedEncodingException;  
  4.   
  5. import javax.servlet.http.HttpServletRequest;  
  6. import javax.servlet.http.HttpSession;  
  7.   
  8. import org.oms.qiye.pojo.AccessToken;  
  9. import org.oms.qiye.util.Constants;  
  10. import org.oms.qiye.util.QiYeUtil;  
  11. import org.oms.qiye.util.Result;  
  12. import org.springframework.stereotype.Controller;  
  13. import org.springframework.web.bind.annotation.RequestMapping;  
  14. import org.springframework.web.bind.annotation.RequestParam;  
  15. /** 
  16.  * OAuth2 处理控制器 
  17.  * @author Sunlight 
  18.  * 
  19.  */  
  20. @Controller  
  21. public class OAuth2Controller {  
  22.     /** 
  23.      * 构造参数并将请求重定向到微信API获取登录信息 
  24.      *  
  25.      * @param index 
  26.      * @return 
  27.      */  
  28.     @RequestMapping(value = { "/oauth2.do""/oauth2" })  
  29.     public String Oauth2API(HttpServletRequest request, @RequestParam String resultUrl) {  
  30.         // 此处可以添加获取持久化的数据,如企业号id等相关信息  
  31.         String CropId = Constants.CORPID;  
  32.         String redirectUrl = "";  
  33.         if (resultUrl != null) {  
  34.            //String reqUrl =request.getLocalAddr();  
  35.             //TODO 此处把参数"reqUrl"拼接成你自己的URL
  36.             String reqUrl = "hhxxmm.nat123.net/QiyeProject"
  37.      
  38.             String backUrl ="http://" + reqUrl + "/oauth2url.do?oauth2url=" + resultUrl;  
  39.             System.out.println("backUrl="+backUrl);  
  40.             redirectUrl = oAuth2Url(CropId, backUrl);  
  41.         }  
  42.         return "redirect:" + redirectUrl;  
  43.     }  
  44.   
  45.     /** 
  46.      * 根据code获取Userid后跳转到需要带用户信息的最终页面 
  47.      *  
  48.      * @param request 
  49.      * @param code 
  50.      *            获取微信重定向到自己设置的URL中code参数 
  51.      * @param oauth2url 
  52.      *            跳转到最终页面的地址 
  53.      * @return 
  54.      */  
  55.     @RequestMapping(value = { "/oauth2url.do" })  
  56.     public String Oauth2MeUrl(HttpServletRequest request, @RequestParam String code, @RequestParam String oauth2url) {  
  57.         AccessToken accessToken = QiYeUtil.getAccessToken(Constants.CORPID, Constants.Secret);  
  58.         HttpSession session = request.getSession();  
  59.         if (accessToken != null && accessToken.getToken() != null) {  
  60.             String Userid = getMemberGuidByCode(accessToken.getToken(), code, Constants.AGENTID);  
  61.             if (Userid != null) {  
  62.                 session.setAttribute("UserId", Userid);  
  63.             }  
  64.         }  
  65.         // 这里简单处理,存储到session中  
  66.         return "redirect:" + oauth2url;  
  67.     }  
  68.   
  69.     /** 
  70.      * 构造带员工身份信息的URL 
  71.      *  
  72.      * @param corpid 
  73.      *            企业id 
  74.      * @param redirect_uri 
  75.      *            授权后重定向的回调链接地址,请使用urlencode对链接进行处理 
  76.      * @param state 
  77.      *            重定向后会带上state参数,企业可以填写a-zA-Z0-9的参数值 
  78.      * @return 
  79.      */  
  80.     private String oAuth2Url(String corpid, String redirect_uri) {  
  81.         try {  
  82.             redirect_uri = java.net.URLEncoder.encode(redirect_uri, "utf-8");  
  83.         } catch (UnsupportedEncodingException e) {  
  84.             e.printStackTrace();  
  85.         }  
  86.         String oauth2Url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + corpid + "&redirect_uri=" + redirect_uri  
  87.                 + "&response_type=code&scope=snsapi_base&state=sunlight#wechat_redirect";  
  88.         System.out.println("oauth2Url=" + oauth2Url);  
  89.         return oauth2Url;  
  90.     }  
  91.   
  92.     /** 
  93.      * 调用接口获取用户信息 
  94.      *  
  95.      * @param token 
  96.      * @param code 
  97.      * @param agentId 
  98.      * @return 
  99.      * @throws SQLException 
  100.      * @throws RemoteException 
  101.      */  
  102.     public String getMemberGuidByCode(String token, String code, int agentId) {  
  103.         System.out.println("code==" + code + "\ntoken=" + token + "\nagentid=" + agentId);  
  104.         Result<String> result = QiYeUtil.oAuth2GetUserByCode(token, code, agentId);  
  105.         System.out.println("result=" + result);  
  106.         if (result.getErrcode() == "0") {  
  107.             if (result.getObj() != null) {  
  108.                 // 此处可以通过微信授权用code还钱的Userid查询自己本地服务器中的数据  
  109.                 return result.getObj();  
  110.             }  
  111.         }  
  112.         return "";  
  113.     }  
  114.   
  115. }  

需要验证OAuth2控制器UserController

  1. package org.oms.qiye.web;  
  2.   
  3. import javax.servlet.http.HttpServletRequest;  
  4. import javax.servlet.http.HttpSession;  
  5. import org.oms.qiye.interceptor.OAuthRequired;  
  6. import org.springframework.stereotype.Controller;  
  7. import org.springframework.ui.Model;  
  8. import org.springframework.web.bind.annotation.RequestMapping;  
  9. /** 
  10.  * 需要验证OAuth2控制器 
  11.  * @author Sunlight 
  12.  * 
  13.  */  
  14. @Controller  
  15. public class UserController {  
  16.     /** 
  17.      * 加载个人信息,此处添加了@OAuthRequired注解 
  18.      * @param model 
  19.      * @return 
  20.      */  
  21.     @RequestMapping(value={"/userInfo.do"})  
  22.     @OAuthRequired  
  23.     public String load(HttpServletRequest request,Model model){  
  24.         System.out.println("Load a User!");  
  25.         HttpSession session = request.getSession();  
  26.         model.addAttribute("Userid", session.getAttribute("Userid"));  
  27.         return "user";  
  28.     }  
  29. }  
     
/**
 * 需要验证OAuth2控制器
 * @author Sunlight
 *
 */
@Controller
public class UserController {
	/**
	 * 加载个人信息,此处添加了@OAuthRequired注解
	 * @param model
	 * @return
	 */
	@RequestMapping(value={"/userInfo.do"})
	@OAuthRequired
	public String load(HttpServletRequest request,Model model){
		System.out.println("Load a User!");
		HttpSession session = request.getSession();
		model.addAttribute("Userid", session.getAttribute("Userid"));
		return "user";
	}
}

3,企业号后台配置:

  (1)给应用配置可信域名
微信企业号OAuth2验证接口的使用
注:如果你的网络是局域网,映射外网工具可使用nat123
 (2)开启回调模式
微信企业号OAuth2验证接口的使用
  (3)配置企业服务器:
微信企业号OAuth2验证接口的使用

 (4)自定义菜单:
微信企业号OAuth2验证接口的使用
按钮名称:个人信息
链接 http://hhxxmm.nat123.net/QiyeProject/userInfo.do

微信企业号OAuth2验证接口的使用
微信企业号OAuth2验证接口的使用
配置好后,手机进入微信企业号,点击按钮“个人信息”,控制台打印出你的userID。

4,总结:

微信提供了OAuth2验证接口,我们可以灵活使用。

微信企业号OAuth2验证接口的使用

上一篇:【转载】微信公众平台java开发详解(工程代码+解析)


下一篇:微信开放平台中的 网页授权出问题了