以微信为入口的微信企业号第三方应用,难免需要获取用户个人信息。企业应用中的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
- package org.oms.qiye.interceptor;
- import java.io.UnsupportedEncodingException;
- import java.lang.reflect.Method;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.servlet.http.HttpSession;
- import org.springframework.web.method.HandlerMethod;
- import org.springframework.web.servlet.HandlerInterceptor;
- import org.springframework.web.servlet.ModelAndView;
- public class OAuth2Interceptor implements HandlerInterceptor {
- /**
- * 在DispatcherServlet完全处理完请求后被调用
- * 当有拦截器抛出异常时,会从当前拦截器往回执行所有的拦截器的afterCompletion()
- */
- @Override
- public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
- System.out.println("**执行顺序: 3、afterCompletion**");
- }
- /**
- * 在业务处理器处理请求执行完成后,生成视图之前执行的动作
- */
- @Override
- public void postHandle(HttpServletRequest request, HttpServletResponse response, Object arg2, ModelAndView modelAndView) throws Exception {
- System.out.println("**执行顺序: 2、postHandle**");
- }
- /**
- * 在业务处理器处理请求之前被调用 如果返回false 从当前的拦截器往回执行所有拦截器的afterCompletion(),再退出拦截器链
- * 如果返回true 执行下一个拦截器,直到所有的拦截器都执行完毕 再执行被拦截的Controller 然后进入拦截器链,
- * 从最后一个拦截器往回执行所有的postHandle() 接着再从最后一个拦截器往回执行所有的afterCompletion()
- */
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
- System.out.println("**执行顺序: 1、preHandle**");
- String url = request.getRequestURL().toString();
- HttpSession session = request.getSession();
- // 先判断是否有注解
- HandlerMethod handlerMethod = (HandlerMethod) handler;
- Method method = handlerMethod.getMethod();
- OAuthRequired annotation = method.getAnnotation(OAuthRequired.class);
- if (annotation != null) {
- System.out.println("OAuthRequired:你的访问需要获取登录信息!");
- Object objUid = session.getAttribute("UserId");
- if (objUid == null) {
- String resultUrl = request.getRequestURL().toString();
- String param=request.getQueryString();
- if(param!=null){
- resultUrl+= "?" + param;
- }
- System.out.println("resultUrl="+resultUrl);
- try {
- resultUrl = java.net.URLEncoder.encode(resultUrl, "utf-8");
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- //请求的路径
- String contextPath=request.getContextPath();
- response.sendRedirect(contextPath + "/oauth2.do?resultUrl=" + resultUrl);
- return false;
- }
- }
- return true;
- }
- }
验证OAuth2注解OAuthRequired
- package org.oms.qiye.interceptor;
- import java.lang.annotation.*;
- /**
- * 验证OAuth2注解
- * @author Sunlight
- *
- */
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.METHOD)
- public @interface OAuthRequired {
- }
常量类,此处可以替换为持久化数据读取;
- package org.oms.qiye.util;
- public class Constants {
- /**
- * 常量说明:
- * 此处定义的常量需要持久化,可以保存在数据库中,在需要的地方读取。
- * 在多企业号中,最好以每个应用来定义。
- */
- public static final int AGENTID = 1;
- public static final String TOKEN = "sunlight";
- public static final String CORPID = "你的企业号ID";
- public static final String Secret = "你的企业号_ACCESS_TOKEN";
- public static final String encodingAESKey = "s8vFF4f6AWay3uAdJh79WD6imaam4BV6Kl4eL4UzgfM";
- }
OAuth2 处理控制器OAuth2Controller
- package org.oms.qiye.web;
- import java.io.UnsupportedEncodingException;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpSession;
- import org.oms.qiye.pojo.AccessToken;
- import org.oms.qiye.util.Constants;
- import org.oms.qiye.util.QiYeUtil;
- import org.oms.qiye.util.Result;
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestParam;
- /**
- * OAuth2 处理控制器
- * @author Sunlight
- *
- */
- @Controller
- public class OAuth2Controller {
- /**
- * 构造参数并将请求重定向到微信API获取登录信息
- *
- * @param index
- * @return
- */
- @RequestMapping(value = { "/oauth2.do", "/oauth2" })
- public String Oauth2API(HttpServletRequest request, @RequestParam String resultUrl) {
- // 此处可以添加获取持久化的数据,如企业号id等相关信息
- String CropId = Constants.CORPID;
- String redirectUrl = "";
- if (resultUrl != null) {
- //String reqUrl =request.getLocalAddr();
- //TODO 此处把参数"reqUrl"拼接成你自己的URL
- String reqUrl = "hhxxmm.nat123.net/QiyeProject"
- String backUrl ="http://" + reqUrl + "/oauth2url.do?oauth2url=" + resultUrl;
- System.out.println("backUrl="+backUrl);
- redirectUrl = oAuth2Url(CropId, backUrl);
- }
- return "redirect:" + redirectUrl;
- }
- /**
- * 根据code获取Userid后跳转到需要带用户信息的最终页面
- *
- * @param request
- * @param code
- * 获取微信重定向到自己设置的URL中code参数
- * @param oauth2url
- * 跳转到最终页面的地址
- * @return
- */
- @RequestMapping(value = { "/oauth2url.do" })
- public String Oauth2MeUrl(HttpServletRequest request, @RequestParam String code, @RequestParam String oauth2url) {
- AccessToken accessToken = QiYeUtil.getAccessToken(Constants.CORPID, Constants.Secret);
- HttpSession session = request.getSession();
- if (accessToken != null && accessToken.getToken() != null) {
- String Userid = getMemberGuidByCode(accessToken.getToken(), code, Constants.AGENTID);
- if (Userid != null) {
- session.setAttribute("UserId", Userid);
- }
- }
- // 这里简单处理,存储到session中
- return "redirect:" + oauth2url;
- }
- /**
- * 构造带员工身份信息的URL
- *
- * @param corpid
- * 企业id
- * @param redirect_uri
- * 授权后重定向的回调链接地址,请使用urlencode对链接进行处理
- * @param state
- * 重定向后会带上state参数,企业可以填写a-zA-Z0-9的参数值
- * @return
- */
- private String oAuth2Url(String corpid, String redirect_uri) {
- try {
- redirect_uri = java.net.URLEncoder.encode(redirect_uri, "utf-8");
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- String oauth2Url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + corpid + "&redirect_uri=" + redirect_uri
- + "&response_type=code&scope=snsapi_base&state=sunlight#wechat_redirect";
- System.out.println("oauth2Url=" + oauth2Url);
- return oauth2Url;
- }
- /**
- * 调用接口获取用户信息
- *
- * @param token
- * @param code
- * @param agentId
- * @return
- * @throws SQLException
- * @throws RemoteException
- */
- public String getMemberGuidByCode(String token, String code, int agentId) {
- System.out.println("code==" + code + "\ntoken=" + token + "\nagentid=" + agentId);
- Result<String> result = QiYeUtil.oAuth2GetUserByCode(token, code, agentId);
- System.out.println("result=" + result);
- if (result.getErrcode() == "0") {
- if (result.getObj() != null) {
- // 此处可以通过微信授权用code还钱的Userid查询自己本地服务器中的数据
- return result.getObj();
- }
- }
- return "";
- }
- }
需要验证OAuth2控制器UserController
- package org.oms.qiye.web;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpSession;
- import org.oms.qiye.interceptor.OAuthRequired;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.RequestMapping;
- /**
- * 需要验证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";
- }
-
}
/** * 需要验证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)给应用配置可信域名
注:如果你的网络是局域网,映射外网工具可使用nat123
(2)开启回调模式
(3)配置企业服务器:
(4)自定义菜单:
按钮名称:个人信息
链接 http://hhxxmm.nat123.net/QiyeProject/userInfo.do
配置好后,手机进入微信企业号,点击按钮“个人信息”,控制台打印出你的userID。
4,总结:
微信提供了OAuth2验证接口,我们可以灵活使用。