001/** 002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.jboot.wechat.interceptor; 017 018import com.jfinal.aop.Interceptor; 019import com.jfinal.aop.Invocation; 020import com.jfinal.core.JFinal; 021import com.jfinal.weixin.sdk.api.ApiConfigKit; 022import com.jfinal.weixin.sdk.api.ApiResult; 023import io.jboot.utils.StrUtil; 024import io.jboot.wechat.controller.JbootWechatController; 025 026import javax.servlet.http.HttpServletRequest; 027 028/** 029 * 获取用户信息的连接器。 030 * 相关文档:https://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html 031 */ 032public class WechatUserInterceptor implements Interceptor { 033 034 035 public static final String AUTHORIZE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize" 036 + "?appid={appid}" 037 + "&redirect_uri={redirecturi}" 038 + "&response_type=code" 039 + "&scope=snsapi_userinfo" 040 + "&state=235#wechat_redirect"; 041 042 043 public static final String BASE_AUTHORIZE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize" 044 + "?appid={appid}" 045 + "&redirect_uri={redirecturi}" 046 + "&response_type=code" 047 + "&scope=snsapi_base" 048 + "&state=235#wechat_redirect"; 049 050 051 @Override 052 public void intercept(Invocation inv) { 053 054 JbootWechatController controller = (JbootWechatController) inv.getController(); 055 056 /** 057 * 是否允许访问,默认情况下只有是微信浏览器允许访问 058 */ 059 if (controller.isAllowVisit()) { 060 doIntercept(inv); 061 return; 062 } 063 064 controller.doNotAllowVisitRedirect(); 065 066 } 067 068 private void doIntercept(Invocation inv) { 069 070 JbootWechatController controller = (JbootWechatController) inv.getController(); 071 072 073 /** 074 * isFromBaseScope 表示 静默授权过来的 075 * 静默授权过来是无法获取用户的基本信息的,只能获得openid, 076 * 这个时候,只能查看openid在数据库里是否已经存在, 077 * 如果存在,则已经标示到了当前用户了 078 * 如果不存在,则通过snsapi_userinfo方式去获取,这样就可以获取到全部资料,保存到数据库 079 */ 080 boolean isFromBaseScope = isFromBaseScope(inv); 081 082 if (isFromBaseScope) { 083 084 String openid = inv.getController().getSessionAttr(JbootWechatController.SESSION_WECHAT_OPEN_ID); 085 Object user = controller.doGetUserByOpenId(openid); 086 if (user != null) { 087 controller.setAttr(JbootWechatController.ATTR_USER_OBJECT, user); 088 inv.invoke(); 089 return; 090 } 091 } 092 093 String wechatUserJson = controller.getSessionAttr(JbootWechatController.SESSION_WECHAT_USER_JSON); 094 if (validateUserJson(wechatUserJson)) { 095 Object user = controller.doSaveOrUpdateUserByApiResult(ApiResult.create(wechatUserJson)); 096 if (user == null) { 097 controller.renderText("can not save or update user when get user from wechat"); 098 return; 099 } 100 controller.setAttr(JbootWechatController.ATTR_USER_OBJECT, user); 101 inv.invoke(); 102 return; 103 } 104 105 106 //移除脏数据后,再次进入授权页面 107 controller.clearWechatSession(); 108 109 110 String appid = ApiConfigKit.getAppId(); 111 112 HttpServletRequest request = controller.getRequest(); 113 // 获取用户将要去的路径 114 String queryString = request.getQueryString(); 115 116 // 被拦截前的请求URL 117 String toUrl = request.getRequestURI(); 118 if (StrUtil.isNotBlank(queryString)) { 119 toUrl = toUrl.concat("?").concat(queryString); 120 } 121 122 123 String controllerKey = inv.getControllerPath(); 124 String callbackControllerKey = controllerKey + "/wechatCallback"; 125 126 if (!JFinal.me().getAllActionKeys().contains(callbackControllerKey)) { 127 callbackControllerKey = controllerKey.substring(0, controllerKey.lastIndexOf("/")) + "/wechatCallback"; 128 } 129 130 String redirectUrl = controller.getBaseUrl() + callbackControllerKey + "?goto=" + StrUtil.urlEncode(toUrl); 131 132 redirectUrl = StrUtil.urlEncode(redirectUrl); 133 String authUrl = isFromBaseScope ? AUTHORIZE_URL : BASE_AUTHORIZE_URL; 134 String url = authUrl.replace("{redirecturi}", redirectUrl).replace("{appid}", appid.trim()); 135 controller.redirect(url); 136 } 137 138 /** 139 * 验证微信用户的json信息是否正确 140 * 141 * @param wechatUserJson 142 * @return 143 */ 144 protected boolean validateUserJson(String wechatUserJson) { 145 return StrUtil.isNotBlank(wechatUserJson) 146 && wechatUserJson.contains("openid") 147 && wechatUserJson.contains("nickname") //包含昵称 148 && wechatUserJson.contains("headimgurl"); //包含头像 149 } 150 151 protected boolean isFromBaseScope(Invocation inv) { 152 String scope = inv.getController().getSessionAttr(JbootWechatController.SESSION_WECHAT_SCOPE); 153 return scope != null && "snsapi_base".equalsIgnoreCase(scope); 154 } 155 156 157}