原先公众号的登录注册由于session的频繁失效,导致需要用户频繁登录,这样用户体验极差。我试过增大session的失效时间,但是随着用户的增多,过长生命周期的session对服务器来说也是一笔大开支;我接着以openId为key将用户的登录状态保存到redis数据库中,但是按照之前项目的设计,只有从公众号菜单栏点击进来的链接才能获取到openId,对于非菜单栏的链接,是获取不到openId的,去网上搜索了很久,变换了无数的关键词去搜索,都没能找到满意的方案,就在快放弃之时,突然灵光一闪,脑海中浮现出一个使用微信的静默授权去获取的openId的思路,这对于刚接触公众号开发的我来说,多少还是有些小成就滴。

具体的逻辑是这样的:用户注册的时候,暂时不获取微信openId,做的只是简单的在我们自己的网站(后面统一称为第三方网站)注册账户,注册成功后直接跳转到登录界面。登录的时候,前端调用直接发ajax请求访问后端提供的接口,这个接口其实也不直接涉及微信openId的相关信息,登录做的只是去第三方网站校验当前登录用户的用户名和密码是否正确,校验通过之后,这个登录接口会返回一个后台拼接好的发送微信静默授权的url(简称wxUrl),然后前端直接调用 localtion.href=wxUrl 方法执行这个wxUrl链接。而真正将用户微信和第三方账户绑定在一起的操作,是在这个wxUrl里设置的回调地址里(这个接口是由第三方自己定义的接口)完成的,具体的等下直接看代码。至于如何实现用户在公众号在第一次登录后,用户的登录状态为永久登录,这就需要用到filter过滤器(也不一定要用这个,我这个没办法,项目一开始没有用到框架,如果你用的springmvc,可以使用拦截器)对用户的请求进行拦截,拦截的目的主要是判断当前session是否已过期(通过判断session域对象中是否能获取到openId、用户名等你定义的信息)。如果session域对象中没有openId,则再次发送微信静默授权获取openId,因为第一次登录的时候,我们已经以openId为key将一些信息保存到redis数据库中,此次通过静默授权获取到openId,相当于拿到了redis的key,然后直接取出该key对应的redis的value,重新给当前session复制一遍用户的信息,然后继续用户原来的请求就好了。

后面分享的代码省去了一些比较隐私的个人业务,希望各位理解;顺便声明,分享出来的都是业务层的代码,至于原生servlet的控制层的代码,我就不写了,实在不会的怕是得回去复习复习了。

下面开始上代码,首先是用户的登录相关的类,这里的登录接口,需要

package servlet;import java.util.UUID;import javax.servlet.http.HttpServletRequest;import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;import pojo.Result;
import util.Constant;
import util.redis.RedisUtils;public class UserLoginService {private static final Logger logger = Logger.getLogger(UserLoginService.class);/*** 登录接口* @param request* @return*/public Result login(HttpServletRequest request) {Result result = new Result();try {//核心业务隐身符1:此处省略传入参数的校验,记住一点:永远不要相信前端传来的数据,所有核心数据后台都要校验//核心业务隐身符2:此处继续省略判断用户名和密码是否正确的检验,这里就要涉及到数据库的相关操作了,此处不赘述,假设用户名和密码校验通过了,记为b=trueboolean b=true;if(b){//高能预警,核心代码来了//设置令牌,这个很关键,用来保存我们自己网站的用户资料,如用户名,id等String uuid = UUID.randomUUID().toString().replaceAll("-", "");String token =name + "##"  +id ;RedisUtils.set(uuid, token, 60);// 设置token有效期为60秒,这个时间不要设置太长,并且一旦使用后立即失效//用户微信获取授权成功之后,会将请求转发回你指定的回调地址,String redirectUrl = "https://网站域名/项目名/wxLoginRedirectServlet";//需要对你的回调地址进行编码,这个步很重要redirectUrl=java.net.URLEncoder.encode(redirectUrl, "utf-8");//当用户登录校验成功之后,将这个url返回给前端的路径,前端需要调用location.href=wxUrl 方法.//Constant.APP_ID是 第三方用户唯一凭证,需要你登录自己的公众号查找,具体方法请自行百度//&connect_redirect=1这个参数很重要,微信服务器有时候会不太靠谱,会对这个请求处理两次,实际生产环境出现过这个问题,故加上这个参数String wxUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + Constant.APP_ID+ "&redirect_uri=" + redirectUrl + "&response_type=code&scope=snsapi_userinfo&state=" + uuid+ "&connect_redirect=1#wechat_redirect";logger.info("最终生成的微信授权路径:"+wxUrl);result.setUrl(wxUrl);result.setSuccess(true);result.setMsg("信息验证通过");}else{//如果用户名和密码不存在,返回错误提示即可,更严格些的,应该做用户每日输入次数的记录与限制,比如连续输错三次,需要输入图形验证码;连续输错6次,则只能重置登录密码或明日再来result.setSuccess(false);result.setMsg("用户名或密码错误");return result;}} catch (Exception e) {result.setSuccess(false);result.setMsg("网络异常:" + e.getMessage());logger.info("网络异常:" + e.getMessage());} return result;}}

Result.java类不提供,这个只是一个简单的实体类,你要喜欢,用Map来存储返回值也是一样的,大家真的没必要纠结这一点。RedisUtils.java工具类,请访问我的另一篇博客https://blog.csdn.net/weixin_42023666/article/details/89287418 ,直接复制粘贴到你的项目便能使用。

好吧,我还是太心软了,怕大家不记得原生servlet给ajax请求返回数据的方式了,下面分享一个给大家参考一下,至于web.xml文件中的servlet请求的映射路径,大家自己动手了,全当复习吧。

package servlet;import java.io.IOException;
import java.io.PrintWriter;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import com.alibaba.fastjson.JSON;import pojo.Result;/*** * @ClassName: JsonServlet  * @Description: TODO(这里用一句话描述这个类的作用)  * @author hqq  **/
public class UserLoginServlet extends HttpServlet {private static final long serialVersionUID = 1L;private UserLoginService service=new UserLoginService();public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {Result result=service.login(request);String json = JSON.toJSONString(result);PrintWriter out = response.getWriter();out.write(json);out.close();}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {this.doGet(request, response);}
}

下面分享的就是大家最喜欢的,我们前面的登录接口中拼接的微信静默授权url里面的回调接口,即 https://网站域名/项目名/wxLoginRedirectServlet  这个回调接口的代码了,大家接好了:

package servlet;import java.sql.SQLException;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;import pojo.WeixinOauth2Token;
import pojo.WeixinUserInfo;
import util.WXAdvancedUtil;
import util.WXUtil;
import util.redis.RedisUtils;/**  * @ClassName: RedirectServlet  * @Description: TODO(这里用一句话描述这个类的作用)  * @author hqq  *    */
@SuppressWarnings("serial")
public class WxLoginRedirectServlet extends HttpServlet{private static final Logger logger = Logger.getLogger(WxLoginRedirectServlet.class);public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {this.doPost(request, response);}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {HttpSession session = request.getSession();request.setCharacterEncoding("UTF-8");response.setCharacterEncoding("UTF-8");logger.info("获取到请求的服务器地址:"+request.getServerName());//你的网站的全域名,https://www.*.com/ ;//因为微信完 第三方网站的微信授权请求的后,是使用转发方式转发到我们制定的url的,所以此处获取的域名还是我们自己网站的域名。这个判断也是为了防止恶意请求String mainUrl="";if(!mainUrl.contains(request.getServerName())){logger.info("非法请求:"+mainUrl);response.sendRedirect("/你的项目名/个人中心.jsp");return;}String code = request.getParameter("code");//获取到code,这个code应该是微信那边定义的String state=request.getParameter("state");//第三方网站(即我们自己)自定义的参数,可以存储一些重要信息和防伪信息,因为这个接口是完全暴露的,所以必须要有防伪措施,防止恶意请求来搞事//如果这两个字段都为空值,就可以判定为而已请求if(StringUtils.isBlank(code)||StringUtils.isBlank(state)){logger.info("非法请求,缺少必要的参数");return;}logger.info("获取到的code是 :" + code+",state="+state);String openId = null;// 用户同意授权,默认强行同意if (!"authdeny".equals(code)) {logger.info("授权成功----");String appId = Constant.APP_ID;// 第三方用户唯一凭证String appSecret = Constant.APP_SECRET;// 第三方用户唯一凭证密钥// 获取网页授权access_tokenWeixinOauth2Token weixinOauth2Token = WXAdvancedUtil.getOauth2AccessToken(appId, appSecret, code);if (weixinOauth2Token != null) {// 用户标识openId = weixinOauth2Token.getOpenId();// 获取用户信息}logger.info("微信授权获取到用户的openId是:" + openId);//判断redis数据库中,是否存在以这个用户的openId为key的键值,对应的value是用户初次绑定时存储的信息String userInfo = RedisUtils.get(openId);if(StringUtils.isNotBlank(userInfo)){//如果存在,说明用户不是第一次绑定//判断该微信号绑定的是否是该手机号//userInfo =name + "##"  +id ;String[] infos = userInfo.split("##");logger.info("最初的session是失效了,但是redis中的值还在");//本次session会话为新 会话,可以保存一些你必须要的数据session.setAttribute("name", infos[0]);//session.setAttribute("id", infos[1]);session.setAttribute("openId", openId);session.setMaxInactiveInterval(60*60);//本次的session有效期设置成一个小时,这个配置按需设置,不知道有没有效哈logger.info("session中保存用户信息成功,跳转到原先的执行页面-:"+state);//这是用户权限拦截时,在过滤的过程中response.sendRedirect(state);//继续走用户原来的请求return;}else{//用户第一次绑定微信公众号try {String token = RedisUtils.get(state);//从redis数据库获取登录时用户保存的信息//token失效,需要重新登录,理论上token的值设置成60秒有效已经足够,超过这个时间,系统理应不予处理if(StringUtils.isBlank(token)){logger.info("本次token失效,绑定失败,重回登录页面");response.sendRedirect("/你的项目名/个人中心.jsp");//重定向到个人中心,由拦截器决定是否放行return;}logger.info("token未失效,token对应的值是:"+token);//token =name + "##"  +id ;String[] split = token.split("##");//核心业务隐身符;此处需判断当前用户id(也就是我们自己网站的用户)是否已经绑定了其它的用户的微信,具体实现方法//是通过用户id去数据库查询用户记录,查询我们自己的数据库中当前用户记录的openId字段,记为dbOpenId;//具体sql省略,每个项目建的表和表字段都不同,所以不要纠结,但是理论上都会有用户id和用户的微信openId一对一的关系存在String dbOpenId="假设从数据库查到的当前用户id对应的openId的值是这个";              //数据库中有该记录if(StringUtils.isNotBlank(dbOpenId)){//1.判断这个openid与当前登录使用的openId是否一致,防止别的微信登录该帐号if(!openId.equals(dbOpenId)){logger.info("该帐号已绑定别的微信帐号,请联系客服解绑后在登录");session.setAttribute("msg", "该帐号已绑定别的微信帐号,请联系客服解绑后在登录");response.sendRedirect("/你的项目名/个人中心.jsp");return;}}else{//没有,是第一次绑定// 获取接口访问凭证String accessToken = WXUtil.getToken(appId, appSecret).getAccessToken();// 获取微信用户的信息WeixinUserInfo wxInfo = WXAdvancedUtil.getUserInfo(accessToken, openId);logger.info("绑定用户openId开始:" + openId + ",用户accessToken:" + accessToken); //判断昵称是否有emoj图片String nickName=wxInfo.getNickname();if(WXUtil.containsEmoji(nickName)){nickName=WXUtil.filterEmoji(nickName);wxInfo.setNickname(nickName);}//核心业务隐身符,将微信用户的信息保存到你的数据库中,方便后期使用,微信用户的具体信息都在WeixinUserInfo类中,大家自己取就好了}session.setAttribute("name", split[0]);session.setAttribute("id", split[1]);session.setAttribute("openId", openId);session.setMaxInactiveInterval(60*60);//本次的session有效期设置成一个小时,这个配置按需设置,不知道有没有效哈RedisUtils.set(openId, token);//redis数据库中保存所有登录的openIdRedisUtils.sAdd("LOGIN_USER_OPENID", openId);response.sendRedirect("/你的项目名/个人中心.jsp");//跳转到个人中心页面return;} catch (Exception e) {logger.info("绑定微信异常:"+e.getMessage());} }}//用户不同意授权,或者用户未绑定微信号,跳转到登录注册页面response.sendRedirect("/你的项目名/个人中心.jsp");//跳转到个人中心页面return;}
}

实体类WeixinOauth2Token.java ,WeixinUserInfo.java 和 工具类WXAdvancedUtil.java ,WXUtil.java 是直接百度的,没什么技术含量,这里顺便贴出来吧:

package pojo;/*** 网页授权信息*/
public class WeixinOauth2Token {// 网页授权接口调用凭证private String accessToken;// 凭证有效时长private int expiresIn;// 用于刷新凭证private String refreshToken;// 用户标识private String openId;// 用户授权作用域private String scope;public String getAccessToken() {return accessToken;}public void setAccessToken(String accessToken) {this.accessToken = accessToken;}public int getExpiresIn() {return expiresIn;}public void setExpiresIn(int expiresIn) {this.expiresIn = expiresIn;}public String getRefreshToken() {return refreshToken;}public void setRefreshToken(String refreshToken) {this.refreshToken = refreshToken;}public String getOpenId() {return openId;}public void setOpenId(String openId) {this.openId = openId;}public String getScope() {return scope;}public void setScope(String scope) {this.scope = scope;}
}

WeixinUserInfo.java

package pojo;/*** 微信用户的基本信息*/
public class WeixinUserInfo {// 用户的标识private String openId;// 关注状态(1是关注,0是未关注),未关注时获取不到其余信息private int subscribe;// 用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间private String subscribeTime;// 昵称private String nickname;// 用户的性别(1是男性,2是女性,0是未知)private int sex;// 用户所在国家private String country;// 用户所在省份private String province;// 用户所在城市private String city;// 用户的语言,简体中文为zh_CNprivate String language;// 用户头像private String headImgUrl;private String unionId;private String remark;private String groupId;private String errcode;private String errmsg;private String accessToken;@Overridepublic String toString() {return "WeixinUserInfo [openId=" + openId + ", subscribe=" + subscribe+ ", subscribeTime=" + subscribeTime + ", nickname=" + nickname+ ", sex=" + sex + ", country=" + country + ", province="+ province + ", city=" + city + ", language=" + language+ ", headImgUrl=" + headImgUrl + ", unionId=" + unionId+ ", remark=" + remark + ", groupId=" + groupId + ", errcode="+ errcode + ", errmsg=" + errmsg + ", accessToken="+ accessToken + "]";}public String getUnionId() {return unionId;}public void setUnionId(String unionId) {this.unionId = unionId;}public String getRemark() {return remark;}public void setRemark(String remark) {this.remark = remark;}public String getGroupId() {return groupId;}public void setGroupId(String groupId) {this.groupId = groupId;}public String getErrcode() {return errcode;}public void setErrcode(String errcode) {this.errcode = errcode;}public String getErrmsg() {return errmsg;}public void setErrmsg(String errmsg) {this.errmsg = errmsg;}public String getAccessToken() {return accessToken;}public void setAccessToken(String accessToken) {this.accessToken = accessToken;}public String getOpenId() {return openId;}public void setOpenId(String openId) {this.openId = openId;}public int getSubscribe() {return subscribe;}public void setSubscribe(int subscribe) {this.subscribe = subscribe;}public String getSubscribeTime() {return subscribeTime;}public void setSubscribeTime(String subscribeTime) {this.subscribeTime = subscribeTime;}public String getNickname() {return nickname;}public void setNickname(String nickname) {this.nickname = nickname;}public int getSex() {return sex;}public void setSex(int sex) {this.sex = sex;}public String getCountry() {return country;}public void setCountry(String country) {this.country = country;}public String getProvince() {return province;}public void setProvince(String province) {this.province = province;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}public String getLanguage() {return language;}public void setLanguage(String language) {this.language = language;}public String getHeadImgUrl() {return headImgUrl;}public void setHeadImgUrl(String headImgUrl) {this.headImgUrl = headImgUrl;}
}

工具类WXAdvancedUtil.java

package util;import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;import javax.net.ssl.HttpsURLConnection;
import javax.servlet.http.HttpServletRequest;import message.resp.Article;
import message.resp.Music;
import net.sf.json.JSONArray;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import others.CommUtil;
import others.FileUpload;
import pojo.SNSUserInfo;
import pojo.Token;
import pojo.WeixinGroup;
import pojo.WeixinMedia;
import pojo.WeixinOauth2Token;
import pojo.WeixinQRCode;
import pojo.WeixinUserInfo;
import pojo.WeixinUserList;/*** 微信高级接口*/
public class WXAdvancedUtil {private static Logger logger = LoggerFactory.getLogger(WXAdvancedUtil.class);/*** 获取网页授权凭证* * @param appId*            公众账号的唯一标识* @param appSecret*            公众账号的密钥* @param code* @return WeixinAouth2Token*/public static WeixinOauth2Token getOauth2AccessToken(String appId,String appSecret, String code) {WeixinOauth2Token wat = null;// 拼接请求地址String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";requestUrl = requestUrl.replace("APPID", appId);requestUrl = requestUrl.replace("SECRET", appSecret);requestUrl = requestUrl.replace("CODE", code);// 获取网页授权凭证JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, "GET", null);if (null != jsonObject) {try {wat = new WeixinOauth2Token();wat.setAccessToken(jsonObject.getString("access_token"));wat.setExpiresIn(jsonObject.getInt("expires_in"));wat.setRefreshToken(jsonObject.getString("refresh_token"));wat.setOpenId(jsonObject.getString("openid"));wat.setScope(jsonObject.getString("scope"));} catch (Exception e) {wat = null;int errorCode = jsonObject.getInt("errcode");String errorMsg = jsonObject.getString("errmsg");logger.info("获取网页授权凭证失败 errcode:{} errmsg:{}", errorCode,errorMsg);}}return wat;}/*** 获取用户信息* * @param accessToken*            接口访问凭证* @param openId*            用户标识* @return WeixinUserInfo*/public static WeixinUserInfo getUserInfo(String accessToken, String openId) {WeixinUserInfo weixinUserInfo = null;// 拼接请求地址String requestUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID";requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);// 获取用户信息JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, "GET", null);if (null != jsonObject) {try {weixinUserInfo = new WeixinUserInfo();// 用户的标识weixinUserInfo.setOpenId(jsonObject.getString("openid"));// 关注状态(1是关注,0是未关注),未关注时获取不到其余信息weixinUserInfo.setSubscribe(jsonObject.getInt("subscribe"));// 用户关注时间weixinUserInfo.setSubscribeTime(jsonObject.getString("subscribe_time"));// 昵称weixinUserInfo.setNickname(jsonObject.getString("nickname"));// 用户的性别(1是男性,2是女性,0是未知)weixinUserInfo.setSex(jsonObject.getInt("sex"));// 用户所在国家weixinUserInfo.setCountry(jsonObject.getString("country"));// 用户所在省份weixinUserInfo.setProvince(jsonObject.getString("province"));// 用户所在城市weixinUserInfo.setCity(jsonObject.getString("city"));// 用户的语言,简体中文为zh_CNweixinUserInfo.setLanguage(jsonObject.getString("language"));// 用户头像weixinUserInfo.setHeadImgUrl(jsonObject.getString("headimgurl"));weixinUserInfo.setGroupId(jsonObject.getString("groupid"));weixinUserInfo.setRemark(jsonObject.getString("remark"));weixinUserInfo.setUnionId(jsonObject.getString("unionid"));weixinUserInfo.setAccessToken(accessToken);} catch (Exception e) {if (0 == weixinUserInfo.getSubscribe()) {logger.info("用户{}已取消关注", weixinUserInfo.getOpenId());weixinUserInfo.setSubscribe(weixinUserInfo.getSubscribe());} else {String errorCode = jsonObject.getString("errcode");String errorMsg = jsonObject.getString("errmsg");logger.info("获取用户信息失败 errcode:{} errmsg:{}", errorCode,errorMsg);weixinUserInfo.setErrcode(""+errorCode);weixinUserInfo.setErrmsg(errorMsg);}}}return weixinUserInfo;}}

工具类 WXUtil.java

package util;import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;import net.sf.json.JSONException;
import net.sf.json.JSONObject;import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import pojo.Token;
import pojo.WeixinOauth2Token;/*** 微信开发相关工具*/
public class WXUtil {private static Logger log = LoggerFactory.getLogger(WXUtil.class);/*** 检测是否有emoji字符** @param source* @return 一旦含有就抛出*/public static boolean containsEmoji(String source) {if (StringUtils.isBlank(source)) {return false;}int len = source.length();for (int i = 0; i < len; i++) {char codePoint = source.charAt(i);if (isEmojiCharacter(codePoint)) {//do nothing,判断到了这里表明,确认有表情字符return true;}}return false;}private static boolean isEmojiCharacter(char codePoint) {return (codePoint == 0x0) ||(codePoint == 0x9) ||(codePoint == 0xA) ||(codePoint == 0xD) ||((codePoint >= 0x20) && (codePoint <= 0xD7FF)) ||((codePoint >= 0xE000) && (codePoint <= 0xFFFD)) ||((codePoint >= 0x10000) && (codePoint <= 0x10FFFF));}/*** 过滤emoji 或者 其他非文字类型的字符** @param source* @return*/public static String filterEmoji(String source) {source = source.replaceAll("[\\ud800\\udc00-\\udbff\\udfff\\ud800-\\udfff]", "*");if (!containsEmoji(source)) {return source;//如果不包含,直接返回}//到这里铁定包含StringBuilder buf = null;int len = source.length();for (int i = 0; i < len; i++) {char codePoint = source.charAt(i);if (isEmojiCharacter(codePoint)) {if (buf == null) {buf = new StringBuilder(source.length());}buf.append(codePoint);} else {buf.append("*");}}if (buf == null) {return source;//如果没有找到 emoji表情,则返回源字符串} else {if (buf.length() == len) {//这里的意义在于尽可能少的toString,因为会重新生成字符串buf = null;return source;} else {return buf.toString();}}}/*** 获取接口访问凭证* * @param appid*            凭证* @param appsecret*            密钥* @return*/public static Token getToken(String appid, String appsecret) {Token token = new Token();String accesstoken=null;Connection con = DBUtil.getConnection();try{con.setAutoCommit(false);PreparedStatement ptmt = null;ResultSet rs = null;String sql="select * from table where date_add(updatetime, interval 90 minute)>now() and id=1";ptmt = con.prepareStatement(sql);rs=ptmt.executeQuery();if(rs.next()) { accesstoken=rs.getString(1);}if(StringUtils.isEmpty(accesstoken)){String requestUrl = Constant.TOKEN_URL.replace("APPID", appid).replace("APPSECRET", appsecret);// 发起GET请求获取凭证JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, "GET", null);if (null != jsonObject) {try {accesstoken=jsonObject.getString("access_token");
//                      token.setAccessToken(jsonObject.getString("access_token"));token.setExpiresIn(jsonObject.getInt("expires_in"));sql="update struck2.t_wechat_token set token=?,updatetime=NOW() where id=1";ptmt = con.prepareStatement(sql);ptmt.setString(1, accesstoken);int result = ptmt.executeUpdate();} catch (JSONException e) {token = null;// 获取token失败log.error("获取token失败 errcode:{} errmsg:{}",jsonObject.getInt("errcode"),jsonObject.getString("errmsg"));}}}token.setAccessToken(accesstoken);}catch(Exception e){}finally{try {if (con != null) {con.commit();con.close();}} catch (SQLException e) {try {con.rollback();} catch (Exception e1) {}}}return token;}}

最后分享拦截器,用户通过微信公众号向服务器发起的所有要拥有权限才能访问的请求,都应该通过过滤器进行拦截,过滤器内判断用户session没失效,则放行;session失效,判断是否之前已绑定账户,如果绑定,给当前session存储一些自己需要的信息,重新用户原来的访问;如果没有绑定关系,则需要前往登录绑定,下面上代码:

package web;import java.io.IOException;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;import util.Constant;
import util.redis.RedisUtils;public class wechatFilter implements Filter {private static final Logger logger = Logger.getLogger(wechatFilter.class);@Overridepublic void destroy() {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) request;HttpServletResponse res = (HttpServletResponse) response;HttpSession session = req.getSession();logger.info("开始进入拦截器...");//判断当前用户是否已经登录,因为登录后session域对象会保存该值String openId = (String)session.getAttribute("openId");if(StringUtils.isNotBlank(openId)){//再次判断这个openId是否还存在boolean b = RedisUtils.sIsMember("LOGIN_USER_OPENID", openId);if(b){chain.doFilter(req, response);return ;}else{//二次校验,防止session没失效,但是redis中用户信息已被删除的情况session.invalidate();}}//将用户当前的请求和参数重新拼接,等重新为用户获取权限之后之后再执行该请求logger.info("session失效了,发送静默授权获取openId");String url="https://网站域名"+req.getServletPath();//获取请求的参数String queryString = req.getQueryString();if(null !=queryString){url+="?"+queryString;}logger.info("本次请求的完整url="+url);//编码urlurl = java.net.URLEncoder.encode(url, "utf-8");//重定向的域名String redirectUrl = "https://网站域名/项目名/wxLoginRedirectServlet";redirectUrl = java.net.URLEncoder.encode(redirectUrl, "utf-8");//微信获取用户静默授权的url//Constant.APP_ID是 第三方用户唯一凭证,需要你登录自己的公众号查找,具体方法请自行百度String wxUrl="https://open.weixin.qq.com/connect/oauth2/authorize?appid="+Constant.APP_ID+"&redirect_uri="+redirectUrl+"&response_type=code&scope=snsapi_userinfo&state="+url+"&connect_redirect=1#wechat_redirect";res.sendRedirect(wxUrl);logger.info("拦截结束,跳转到微信授权操作");return;}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}}

至此,你们已经完成了80%,剩下的20%,需要各位根据自己的业务需求添加自己的业务数据和逻辑。大体思路和主要的核心代码已贴出,大家按需cv。至于注册的接口,大家可以根据自己的需求来编写,注册接口没有用户微信openId,所有和微信openId相关的操作,都在过滤器和调用微信静默授权接口后的回调函数中。

如果有更好的方法或者发现了什么问题,欢迎赐教;但是说归说,别爆粗口,我没收谁的钱也没有要求谁来点赞,甚至没有要求谁来看,我只是在自己的一亩三分地里写点小文章,记录一些自己曾经走过的路,然后顺便给以后可能和我有同样问题的人提供一些可能的借鉴,同时希望有人提供更好的思路,让我还能再有所提升。素质不好的人,请远离我的评论区,这样你好,我好,大家都好,谢谢!
--------------------- 
作者:今儿ge休息 
来源:CSDN 
原文:https://blog.csdn.net/weixin_42023666/article/details/89284688 
版权声明:本文为博主原创文章,转载请附上博文链接!

微信用户与第三方网站用户的绑定策略(实现用户第一次登陆后永久免登陆)相关推荐

  1. JavaWeb-网站在线用户信息、网站访问量以及管理踢出用户实例

    转载请注明出处: http://blog.csdn.net/qq_26525215 本文源自[大学之旅_谙忆的博客] 这个稍微比上个版本做得完善了一点,用了JavaBean来封装用户信息,添加了一个管 ...

  2. 域服务器如何限制用户授权访问网站,域控服务器怎么设置用户权限

    域控服务器怎么设置用户权限 内容精选 换一换 如果您需要对华为云上购买的裸金属服务器资源,给企业中的员工设置不同的访问权限,以达到不同员工之间的权限隔离,您可以使用统一身份认证服务(Identity ...

  3. 第三方程序完美整合phpwind8的UC用户中心-教程加P8

    不管phpwind未来路如何走我们都会永远支持!!本教程分析 phpwind的UC用户中心如何整合,和提供从P8分离后的完整P8UC整合接口包. P8UC作用: P8的UC与其它程序的UC通信原理基本 ...

  4. 第三方网站用户和微信用户的绑定方法

    这里要通过OAuth2.0来实现 微信公众平台OAuth2.0授权详细步骤如下: 用户关注微信公众账号. 微信公众账号提供用户请求授权页面URL. 用户点击授权页面URL,将向服务器发起请求 服务器询 ...

  5. PC网站接入微信登陆流程四:后端处理登陆后的code,和获取微信登陆用户的信息

    1.文档在这里 ==>> 授权后接口调用(UnionID) 2.前端登陆成功后,需要提交code给后端,后端接受到请求后,进行处理,下面的例子均为Python版本 第一步:通过code获取 ...

  6. 基于UCenter关联第三方网站与Discuz用户

    https://mo2g.com/view/106/ 基于UCenter用户中心把第三方网站的会员与Discuz关联起来(续1) 基于UCenter用户中心把第三方网站的会员与Discuz关联起来(续 ...

  7. 如何解除Chrome无法安装第三方插件的限制(无法从该网站加载扩展程序和用户脚本)

    2018年6月谷歌宣布将废除 Chrome 扩展的内联安装方式(inline installation).所以说,自Chrome 67版本开始,谷歌调整Chrome的插件安装策略,只允许用户在应用商店 ...

  8. php公众号批量推送,微信公众号文章如何批量发送给指定的用户

    微信公众号文章如何批量发送给指定的用户 导读:小编根据大家的需要整理了一份关于<微信公众号文章如何批量发送给指定的用户>的内容,具体内容:微信公众号的文章群发的时候,会发给所有的用户,但是 ...

  9. Django使用Social-Auth实现微信第三方网站扫码登录

    前言 之前让网页公司制作新官网的时候规划有第三方账号的登录功能,但由于当时的一些开放平台申请步骤比较繁琐(尤其是微信开放平台),所以一直拖延着,到了最近只能自己添加相关的功能. 由于是刚接触Pytho ...

最新文章

  1. 安装开源项目 MultiType (基于 RecyclerView)出现的各种问题 -- 自己的第一篇博客...
  2. dede调用当前顶级栏目名称、ID、url方法
  3. 系统业务逻辑书籍_「樊登读书会强推:免费送10本绝密书」彻底改变你的逻辑思维能力...
  4. 观察者模式与Boost.Signals
  5. 为什么代码规范要求SQL语句不要过多的join?
  6. php raido mysql,linux – 如何停止并修复已失败且I / O挂起的RAID 5阵列?
  7. Sentinel服务熔断Ribbon环境预说_客户自定义限流处理_削峰填谷_流量控制_速率控制_服务熔断_服务降级---微服务升级_SpringCloud Alibaba工作笔记0048
  8. c语言复杂数据类型存储,C语言基础-复杂数据类型
  9. 深入入门正则表达式(java) - 1 - 入门基础
  10. 1、http网络编程——URL、CURL、CURLcode和curl_slist
  11. 汽车理论课后习题matlab程序,汽车理论课后题matlab程序
  12. 使用ffmpeg合并.h264文件
  13. webRTC H265浏览器播放器+metaRTC推流实现webRTC H265解决方案
  14. 宁强天津中学2021高考成绩查询,宁强县天津高级中学教务信息网
  15. 爱国html源码,鼠标点击网页爱国富强民主特效(附代码)
  16. fedora 下常用软件安装
  17. C++阶段06笔记01【基于STL的演讲比赛流程管理系统】
  18. 一个宝藏开源软件,跨平台终端神器 Tabby
  19. 推荐几个设计或写文档时经常用到的无版权的图片库,以备不时这需
  20. 保密相册计算机,隐私加密相册电脑版

热门文章

  1. Ubuntu挂载iso文件和配置apt本地源
  2. 关闭windows笔记本自带键盘
  3. 我为什么要创业?——张林轩
  4. fabric java sdk解析channel.queryTransactionByID(txId)方法的返回值
  5. 【Arduino实验08 红外传感器】
  6. 操作系统笔记(一)——操作系统的定义及作用
  7. linux文件夹内JPG批量转PNG
  8. 百度收录静态html吗,百度收录越多,网站排名就越高吗?
  9. 2022年最新浙江道路运输安全员真题题库及答案
  10. 在单机上通过docker搭建redis集群试验