整合微信登入功能
功能介紹:
使用微信掃碼登入;
首先要了解一個(gè)技術(shù)棧:OAuth2技術(shù)
問題:我們用戶的賬號(hào)信息例如:用戶名,地址,頭像,等信息都是保存在騰訊的數(shù)據(jù)庫,我們應(yīng)該如何訪問呢?
1.使用用戶的用戶名和密碼直接訪問去訪問騰訊的數(shù)據(jù)庫(但是風(fēng)險(xiǎn)極大,密碼可能會(huì)泄露,而且用戶也不愿意給我們)
2.通用開發(fā)者key(和騰訊一起開發(fā)一個(gè)可以共同訪問的公共鑰匙,但是不可能,騰訊不理你)
3.頒發(fā)令牌(OAuth2方式)
騰訊通過用戶授權(quán),頒發(fā)一個(gè)token給你,你可以只用這個(gè)token訪問用戶在騰訊的賬號(hào)信息;
如何整合OAuth2:(微信有官方文檔)
首先你要去微信進(jìn)行申請(qǐng),但是需要商家才可以申請(qǐng);
微信會(huì)給你提供兩個(gè)東西
訪問wx.open.app_id(id)、wx.open.redirect_ur(重定向地址):根據(jù)兩個(gè)信息可以在前端生成微信登入用的二維碼;
@GetMapping("getLoginParam")@ResponseBodypublic Result genQrConnect() {try {//返回給前端的map集合Map<String, Object> map = new HashMap<>();//二維碼的idmap.put("appid", wxed9954c01bb89b47);//固定參數(shù)(作用域)map.put("scope","snsapi_login");//重定向地址String wxOpenRedirectUrl = http://localhost:8160/api/ucenter/wx/callback;//修改編碼方法wxOpenRedirectUrl = URLEncoder.encode(wxOpenRedirectUrl, "utf-8");map.put("redirect_uri",wxOpenRedirectUrl);//狀態(tài)就是當(dāng)前時(shí)間map.put("state",System.currentTimeMillis()+"");return Result.ok(map);} catch (UnsupportedEncodingException e) {e.printStackTrace();return null;}} wx.open.app_id=wxed9954c01bb89b47 wx.open.redirect_url=http://localhost:8160/api/ucenter/wx/callback#用戶掃碼成功后微信會(huì)根據(jù)重定向地址給你發(fā)送
code(臨時(shí)票據(jù)需要通過這個(gè)臨時(shí)票據(jù)訪問微信服務(wù)器得到用戶的openId和token令牌)
state? (狀態(tài)碼)
#接下來需要使用自己的HttpClientUtils工具對(duì)微信的服務(wù)進(jìn)行訪問;
通過HttpClientUtils工具訪問微信的服務(wù)器訪問路徑
#https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code#微信服務(wù)器的固定地址+appid+secret+code+固定寫法;
#得到兩個(gè)值? 用戶的openId和token令牌
@GetMapping("callback")public String callback(String code,String state) {//第一步 獲取臨時(shí)票據(jù) codeSystem.out.println("code:"+code);System.out.println("state"+state);//第二步 拿著code和微信id和秘鑰,請(qǐng)求微信固定地址 ,得到兩個(gè)值//使用code和appid以及appscrect換取access_token// %s 占位符StringBuffer baseAccessTokenUrl = new StringBuffer().append("https://api.weixin.qq.com/sns/oauth2/access_token").append("?appid=%s").append("&secret=%s").append("&code=%s").append("&grant_type=authorization_code");//調(diào)用String.format()完成占位符的字符串的拼接String accessTokenUrl = String.format(baseAccessTokenUrl.toString(),ConstantWxPropertiesUtils.WX_OPEN_APP_ID,ConstantWxPropertiesUtils.WX_OPEN_APP_SECRET,code);//使用httpclient請(qǐng)求這個(gè)地址try {//訪問微信服務(wù)器得到用戶的微信openId、token(令牌)String accesstokenInfo = HttpClientUtils.get(accessTokenUrl);System.out.println("accesstokenInfo:"+accesstokenInfo);String access_token = jsonObject.getString("access_token");String openid = jsonObject.getString("openid");##
一般把openId存放進(jìn)入數(shù)據(jù)庫,作為用戶的唯一標(biāo)識(shí),可以節(jié)省一次訪問;
#如果數(shù)據(jù)庫中沒有openId
再使用httpClientUtils訪問微信服務(wù)器得到用戶具體的數(shù)據(jù)
把用戶數(shù)據(jù)轉(zhuǎn)換成JSONObject對(duì)象
if(userInfo == null) {//第三步 拿著openid 和 access_token請(qǐng)求微信地址,得到掃描人信息String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +"?access_token=%s" +"&openid=%s";String userInfoUrl = String.format(baseUserInfoUrl, access_token, openid);//訪問微信的服務(wù)器String resultInfo = HttpClientUtils.get(userInfoUrl);System.out.println("resultInfo:"+resultInfo);//將用戶的信息轉(zhuǎn)換成為json對(duì)象JSONObject resultUserInfoJson = JSONObject.parseObject(resultInfo);//解析用戶信息//用戶昵稱String nickname = resultUserInfoJson.getString("nickname");//用戶頭像String headimgurl = resultUserInfoJson.getString("headimgurl");#把數(shù)據(jù)存放到數(shù)據(jù)庫,重定向放回給前端顯示;
##這樣子就可以結(jié)束了,但是一般還可以添加綁定手機(jī)操作
前端已經(jīng)得到用戶信息了再返回到這個(gè)頁面進(jìn)行手機(jī)號(hào)綁定;
Map<String,String> map = new HashMap<>();String name = userInfo.getName();if(StringUtils.isEmpty(name)) {name = userInfo.getNickName();}if(StringUtils.isEmpty(name)) {name = userInfo.getPhone();}map.put("name", name);//判斷userInfo是否有手機(jī)號(hào),如果手機(jī)號(hào)為空,返回openid//如果手機(jī)號(hào)不為空,返回openid值是空字符串//前端判斷:如果openid不為空,綁定手機(jī)號(hào),如果openid為空,不需要綁定手機(jī)號(hào)if(StringUtils.isEmpty(userInfo.getPhone())) {map.put("openid", userInfo.getOpenid());} else {map.put("openid", "");}//使用jwt生成token字符串String token = JwtHelper.createToken(userInfo.getId(), name);map.put("token", token);//跳轉(zhuǎn)到前端頁面return "redirect:" + ConstantWxPropertiesUtils.YYGH_BASE_URL + "/weixin/callback?token="+map.get("token")+ "&openid="+map.get("openid")+"&name="+URLEncoder.encode(map.get("name"),"utf-8");} catch (Exception e) {e.printStackTrace();return null;}}####完整代碼:
package com.yygh.user.api;import com.alibaba.fastjson.JSONObject; import com.yygh.Result; import com.yygh.helper.JwtHelper; import com.yygh.model.user.UserInfo; import com.yygh.user.service.UserInfoService; import com.yygh.user.utils.ConstantWxPropertiesUtils; import com.yygh.user.utils.HttpClientUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.HashMap; import java.util.Map;/*** 對(duì)微信的操作* @author 便利店狗砸ha* 使用@Controller注解是為了完成醫(yī)院頁面跳轉(zhuǎn)*/ @Controller @RequestMapping("/api/ucenter/wx") public class WeixinApiController {@Autowiredprivate UserInfoService userInfoService;//生成微信掃描的二維碼//1 生成微信掃描二維碼//返回生成二維碼需要參數(shù)@GetMapping("getLoginParam")@ResponseBodypublic Result genQrConnect() {try {//返回給前端的map集合Map<String, Object> map = new HashMap<>();//二維碼的idmap.put("appid", ConstantWxPropertiesUtils.WX_OPEN_APP_ID);//固定參數(shù)(作用域)map.put("scope","snsapi_login");//重定向地址String wxOpenRedirectUrl = ConstantWxPropertiesUtils.WX_OPEN_REDIRECT_URL;//修改編碼方法wxOpenRedirectUrl = URLEncoder.encode(wxOpenRedirectUrl, "utf-8");map.put("redirect_uri",wxOpenRedirectUrl);//狀態(tài)就是當(dāng)前時(shí)間map.put("state",System.currentTimeMillis()+"");return Result.ok(map);} catch (UnsupportedEncodingException e) {e.printStackTrace();return null;}}@GetMapping("callback")public String callback(String code,String state) {//第一步 獲取臨時(shí)票據(jù) codeSystem.out.println("code:"+code);System.out.println("state"+state);//第二步 拿著code和微信id和秘鑰,請(qǐng)求微信固定地址 ,得到兩個(gè)值//使用code和appid以及appscrect換取access_token// %s 占位符StringBuffer baseAccessTokenUrl = new StringBuffer().append("https://api.weixin.qq.com/sns/oauth2/access_token").append("?appid=%s").append("&secret=%s").append("&code=%s").append("&grant_type=authorization_code");//調(diào)用String.format()完成占位符的字符串的拼接String accessTokenUrl = String.format(baseAccessTokenUrl.toString(),ConstantWxPropertiesUtils.WX_OPEN_APP_ID,ConstantWxPropertiesUtils.WX_OPEN_APP_SECRET,code);//使用httpclient請(qǐng)求這個(gè)地址try {//訪問微信服務(wù)器得到用戶的微信openId、token(令牌)String accesstokenInfo = HttpClientUtils.get(accessTokenUrl);System.out.println("accesstokenInfo:"+accesstokenInfo);//從返回字符串獲取兩個(gè)值 openid 和 access_tokenJSONObject jsonObject = JSONObject.parseObject(accesstokenInfo);String access_token = jsonObject.getString("access_token");String openid = jsonObject.getString("openid");//判斷數(shù)據(jù)庫是否存在微信的掃描人信息//根據(jù)openid判斷UserInfo userInfo = userInfoService.selectWxInfoOpenId(openid);//數(shù)據(jù)庫不存在微信信息if(userInfo == null) {//第三步 拿著openid 和 access_token請(qǐng)求微信地址,得到掃描人信息String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +"?access_token=%s" +"&openid=%s";String userInfoUrl = String.format(baseUserInfoUrl, access_token, openid);//訪問微信的服務(wù)器String resultInfo = HttpClientUtils.get(userInfoUrl);System.out.println("resultInfo:"+resultInfo);//將用戶的信息轉(zhuǎn)換成為json對(duì)象JSONObject resultUserInfoJson = JSONObject.parseObject(resultInfo);//解析用戶信息//用戶昵稱String nickname = resultUserInfoJson.getString("nickname");//用戶頭像String headimgurl = resultUserInfoJson.getString("headimgurl");//獲取掃描人信息添加數(shù)據(jù)庫userInfo = new UserInfo();userInfo.setNickName(nickname);userInfo.setOpenid(openid);userInfo.setStatus(1);userInfo.setPhone("123");userInfoService.save(userInfo);}//返回name和token字符串Map<String,String> map = new HashMap<>();String name = userInfo.getName();if(StringUtils.isEmpty(name)) {name = userInfo.getNickName();}if(StringUtils.isEmpty(name)) {name = userInfo.getPhone();}map.put("name", name);//判斷userInfo是否有手機(jī)號(hào),如果手機(jī)號(hào)為空,返回openid//如果手機(jī)號(hào)不為空,返回openid值是空字符串//前端判斷:如果openid不為空,綁定手機(jī)號(hào),如果openid為空,不需要綁定手機(jī)號(hào)if(StringUtils.isEmpty(userInfo.getPhone())) {map.put("openid", userInfo.getOpenid());} else {map.put("openid", "");}//使用jwt生成token字符串String token = JwtHelper.createToken(userInfo.getId(), name);map.put("token", token);//跳轉(zhuǎn)到前端頁面return "redirect:" + ConstantWxPropertiesUtils.YYGH_BASE_URL + "/weixin/callback?token="+map.get("token")+ "&openid="+map.get("openid")+"&name="+URLEncoder.encode(map.get("name"),"utf-8");} catch (Exception e) {e.printStackTrace();return null;}} }總結(jié)
- 上一篇: iTab新标签页,一款个性化的浏览器起始
- 下一篇: MATLAB/simulink学习笔记(