前言:本項目基於SSM,使用tomcat8、jdk8。
目錄
微信公衆號開發–第三章 註冊&簽到&校驗登錄
0、微信公衆號-用戶登錄&查看信息-時序圖
(高清html,文章末尾百度網盤鏈接自取)
1、獲取用戶基本信息&註冊(對應時序圖的步驟1-7)
1.1、接口代碼(微信後端接口)
/**
* @DESCRIPTION : 與微信第三方交互,從而獲取用戶信息。
* 備註--1、本地啓動前端服務獲取code:
* 由於微信第三方的限制,獲取code的操作,應該只能在微信客戶端實現(官方文檔貌似這個意思,我沒寫過test請求過)。
* 參考博文
* https://blog.csdn.net/Sharylala/article/details/105495723
* 的頁面操作部分,獲取code,而後將code作爲入參調接口getUserInfo
*
* 備註--2、訪問請求鏈接獲取code:
* (自己微信號要關注自己的測試號二維碼)
* 2.1、本地域名,設爲 local.sharylala.test
* 2.2、回調地址,設爲 local.sharylala.test
* 2.3、在微信開發者工具上,訪問
* https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
* 其中APPID改寫爲你的appid值,REDIRECT_URI改寫成你的 http://回調域名,
* scope爲snsapi_base 時 scope=snsapi_base
* scope爲snsapi_userinfo 時 scope=snsapi_userinfo(我測試只用過這個),
* state,重定向後會帶上state參數,開發者可以填寫a-zA-Z0-9的參數值,最多128字節。eg: state=123
* 2.4、點擊"同意"
* 2.5、自動跳轉頁面的地址上的code,五分鐘有效
*
*
*
* @AUTHOR Sharylala
* @DATE : 2020/5/21 10:12 下午
* @param bean
* @param request
* @return: com.sharylala.common.util.Result
*/
@RequestMapping(value = "/getUserInfo", method = RequestMethod.POST)
@ResponseBody
public Result getUserInfo(@RequestBody UserBean bean, HttpServletRequest request) throws Exception {
log.info("----------AuthController:getUserInfo----------");
String code = bean.getCode();
if (code == null || "".equals(code)) {
return result(Constants.RESULT_MESSAGE_EMPTY,"code不能爲空", null);
}
String openid = null;
JSONObject userInfo = new JSONObject();
WeChatAuth wa = new WeChatAuth(appid,appsecret);
/**
* 1、獲取前端傳來的code。
* 請求https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
* 獲取access_token和openid。
* */
openid = wa.getOpenidByAuth(code);
if (null != openid) {
/**
* 2、根據access_token和openid,
* 請求https://api.weixin.qq.com/sns/userinfo?access_token=TOKEN&openid=OPENID&lang=zh_CN
* 拉取用戶信息。
* */
userInfo = wa.getUserInfoByOpenid(openid);
//將拉取的基本信息存進用戶表,略
} else {
return error("獲取openid失敗");
}
if (null == userInfo) {
userInfo = new JSONObject();
log.info("======微信用戶信息獲取失敗====");
return error("獲取用戶信息獲取失敗");
}
return ok("獲取用戶信息獲取成功",userInfo);
}
1.2、接口測試
1.2.1、獲取code
點擊同意後,鏈接裏有code
1.2.2、獲取用戶信息
2、簽到(對應時序圖的步驟8-11)
2.1、接口代碼(簡化版,微信後端和後臺接口)
微信後端簽到接口common/sgin
/**
* @DESCRIPTION : 登陸驗證獲取tokenid接口
* @AUTHOR Sharylala
* @DATE : 2020/5/22 7:11 下午
* @param session
* @return: com.sharylala.common.util.Result
*/
@ResponseBody
@RequestMapping(value = "/sign", method = RequestMethod.GET, produces = "application/json")
public Result sign(HttpSession session) {
String url = Interface.getInstance().get("sign");
String result = (String) getWebClient(url, String.class);
log.info("---------sign:{}------", result);
JSONObject jsonResult = Common.strToJSONObject(result);
if (null == jsonResult) {
return error("接口請求錯誤");
}
String statusCode = jsonResult.getString("statusCode");
if ("200".equals(statusCode)) {
try {
log.info("======sessionId:{}======", session.getId());
JedisUtil.setValue(session.getId() + "_tokenid", jsonResult.getString("data"));
} catch (Exception e) {
e.printStackTrace();
}
}
return result(statusCode, jsonResult.getString("message"), jsonResult.getString("data"));
}
後臺簽到接口user/sign
/**
* @DESCRIPTION :獲取tokenid
* @param request
* @param response
* @return: com.sharylala.common.util.Result
*/
@RequestMapping(value = "/sign", method = RequestMethod.GET, produces = "application/json")
@ResponseBody
public Result sign(@Context HttpServletRequest request, @Context HttpServletResponse response) {
String result = Constants.RESULT_MESSAGE_ERROR;
String message = "獲取tokenid失敗";
String tokenid = "";
String ip = "";
try {
tokenid = Constants.WECHAT_SERVICE_TOKENNAME + CommUtil.getUUID();
ip = CommUtil.getIpAddress(request);
JedisUtil.setValue(tokenid, ip, Constants.WECHAT_SERVICE_TIMEOUT);
result = Constants.RESULT_MESSAGE_SUCCESS;
message = "獲取tokenid成功";
return result(result, message, tokenid);
} catch (Exception e) {
logger.info("tokenid is : " + tokenid + "===========ip is: " + ip);
logger.error(ip + "獲取tokenid失敗! /n 異常信息:" + e.getMessage(), e);
} finally {
logger.info("tokenid is : " + tokenid + "===========ip is: " + ip);
}
logger.info(message);
return result(result, message);
}
2.2、接口測試
3、校驗登錄
3.1、配置web.xml
<!-- 校驗tokenid攔截器-->
<filter>
<filter-name>AuthFilter</filter-name>
<filter-class>com.sharylala.modules.wechatservice.filter.AuthFilter</filter-class>
<init-param>
<param-name>anonUrl</param-name>
<param-value>/auth/getUserInfo,/common/sign,/user/sign</param-value><!--過濾器添加例外url用,隔開-->
</init-param>
<init-param>
<param-name>authc</param-name><!--本系統攔截驗證選項-->
<param-value>true</param-value><!--true需要攔截鑑權,安全性高,攔截未登錄及無權限等訪問;開發時可填false-->
</init-param>
</filter>
<filter-mapping>
<filter-name>AuthFilter</filter-name>
<url-pattern>/fileService/*</url-pattern><!--需要攔截驗證的請求-->
<url-pattern>/business/*</url-pattern>
</filter-mapping>
3.2、實現Filter的攔截類代碼
/**
* @DESCRIPTION: 校驗tokenid攔截類
* @AUTHOR Sharylala
* @DATE 2020/5/23 8:41 下午
*/
public class AuthFilter implements Filter {
public final static Logger logger = LoggerFactory.getLogger(AuthFilter.class);
private boolean authc; //是否開啓攔截
private String[] anonUrlArray; //不攔截的url
private final PathMatcher pathMatcher = new AntPathMatcher();
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String authcStr = filterConfig.getInitParameter("authc");
if (StringUtils.isNotBlank(authcStr)){
this.authc = Boolean.parseBoolean(authcStr);
}
String anonUrl = filterConfig.getInitParameter("anonUrl");
if (StringUtils.isNotBlank(anonUrl)) {
this.anonUrlArray = anonUrl.split(",");
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
if (!authc) {
chain.doFilter(request, response);
return;
} else {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String currentURL = httpRequest.getServletPath();
//過濾白名單
if (isWhiteURL(currentURL)){
chain.doFilter(request, response);
return;
}
Cookie[] cookies = httpRequest.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if ("tokenid".equals(cookie.getName()) && StringUtils.isNotBlank(cookie.getValue())) {
//根據tokenid的值,去查redis有沒有對應的ip(在簽到接口裏value就是用request的ip搞的)
String tokenid = cookie.getValue();
String redis = JedisUtil.getValue(tokenid);
if (StringUtils.isBlank(redis)) {
response.getWriter().print(JSON.toJSONString(new Result(Constants.RESULT_MESSAGE_EXIT, "登錄超時,請重新登錄")));
return;
}
String ip = CommUtil.getIpAddress(httpRequest);
//與request的ip對比
if (ip.equals(redis)) {
logger.info("====ip.equals(redis)====ip: " + ip + " redis: " + redis);
chain.doFilter(request, response);
return;
}
}
}
}
}
} catch (Exception e) {
logger.error("AuthFilter攔截器doFilter方法異常,", e);
}
response.getWriter().print(JSON.toJSONString(new Result("403", "please log in first!", null)));
}
@Override
public void destroy() {
//TODO Auto-generated method stub
}
private boolean isWhiteURL(String currentURL) {
for (String whiteURL : anonUrlArray) {
if (pathMatcher.match(whiteURL, currentURL)) {
return true;
}
}
return false;
}
}
3.3、測試
鏈接:https://pan.baidu.com/s/16-Wq-4VWXbJ_fkQupgLwag 密碼:bj2k