第三方網站微信登陸java代碼實現

1、開發前知識java

一、微信開放平臺與微信公衆平臺的區別git

 1.1 微信公衆平臺:  數據庫

 ① 地址:https://mp.weixin.qq.com/cgi-bin/loginpage?t=wxm2-login&lang=zh_CNjson

 ② 微信公衆平臺面向的是普通的用戶,好比自媒體和媒體,企業官方微信公衆帳號運營人員使用,固然你所在的團隊或者公司有實力去開發一些內容,也能夠調用公衆平臺裏面的接口,好比自定義菜單,自動回覆,查詢功能。api

 1.2 微信開放平臺: 數組

 ① 地址:https://open.weixin.qq.com/服務器

 微信開放平臺:面向的是開發者和第三方獨立軟件開發商。開放平臺的文檔彷佛包含了微信開放平臺文檔裏面的接口。微信

二、微信公衆平臺目前只支持80端口,且項目上傳到服務器上面不容易debug啊?微信開發

解決方法:ngrok 工具,能夠根據本地項目映射成外網能夠訪問的地址、端口,默認映射爲80端口。app

官網: https://dashboard.ngrok.com

存在問題: 每次重啓,域名會變化,都須要項目中、微信公衆平臺配置,付費能夠固定域名。。。

使用方法: ① 註冊後得到一個受權碼,下載 ngrok

      ② 》CMD 進入 ngrok 目錄

       》ngrok authtoken 受權碼

       》ngrok http 8080

      ③看到這個頁面,ngrok就爲你分配了臨時訪問通道成功了^^

2、配置

(每一個微信號能夠申請成爲開發者測試帳號進行微信功能開發的。)

一、在公衆平臺中進行配置:

地址: http://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index  

 ①:配置「接口配置信息」 (Token 在項目中我是配置爲"handsomeKing",沒錯,我就是King ^^)

 url 改成本身映射的域名

 ② 配置「功能服務」 的 「網頁賬號」。注意,是域名

好了,能夠愉快的coding 了!!!

3、能夠開發啦

一、上面的 「接口配置信息」 配置得 wechat/ownerCheck 方法是驗證 這個url 爲我本身的,handsomeKing 就是這個方法中的一個參數。微信這個小朋友會用Get方法帶上4個參數給我服務器: signature(簽名)、timestamp(時間戳)、nonce(隨機數)、echostr(隨機字符串),再加上我們項目中本身配置的 token ,經過檢驗signature對請求進行校驗,若校驗成功則原樣返回echostr,表示接入成功,不然接入失敗:(talk is cheap, show me the code *&)

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

/**

* 微信消息接收和token驗證

* @param model

* @param request

* @param response

* @throws IOException

*/

@RequestMapping("/ownerCheck")

public void ownerCheck(Model model, HttpServletRequest request,HttpServletResponse response) throws IOException {

System.out.println(111);

boolean isGet = request.getMethod().toLowerCase().equals("get");

PrintWriter print;

if (isGet) {

 // 微信加密簽名

 String signature = request.getParameter("signature");

 // 時間戳

 String timestamp = request.getParameter("timestamp");

 // 隨機數

 String nonce = request.getParameter("nonce");

 // 隨機字符串

 String echostr = request.getParameter("echostr");

 // 經過檢驗signature對請求進行校驗,若校驗成功則原樣返回echostr,表示接入成功,不然接入失敗

 if (signature != null && CheckoutUtil.checkSignature(signature, timestamp, nonce)) {

 try {

  print = response.getWriter();

  print.write(echostr);

  print.flush();

 } catch (IOException e) {

  e.printStackTrace();

 }

 }

}

}

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

import java.security.MessageDigest;

import java.security.NoSuchAlgorithmException;

 

public class CheckoutUtil {

 // 與接口配置信息中的Token要一致

 private static String token = "handsomeKing";

 

 /**

 * 驗證簽名

 *

 * @param signature

 * @param timestamp

 * @param nonce

 * @return

 */

 public static boolean checkSignature(String signature, String timestamp, String nonce) {

 String[] arr = new String[] { token, timestamp, nonce };

 // 將token、timestamp、nonce三個參數進行字典序排序

 // Arrays.sort(arr);

 sort(arr);

 StringBuilder content = new StringBuilder();

 for (int i = 0; i < arr.length; i++) {

  content.append(arr[i]);

 }

 MessageDigest md = null;

 String tmpStr = null;

 

 try {

  md = MessageDigest.getInstance("SHA-1");

  // 將三個參數字符串拼接成一個字符串進行sha1加密

  byte[] digest = md.digest(content.toString().getBytes());

  tmpStr = byteToStr(digest);

 } catch (NoSuchAlgorithmException e) {

  e.printStackTrace();

 }

 content = null;

 // 將sha1加密後的字符串可與signature對比,標識該請求來源於微信

 return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;

 }

 

 /**

 * 將字節數組轉換爲十六進制字符串

 *

 * @param byteArray

 * @return

 */

 private static String byteToStr(byte[] byteArray) {

 String strDigest = "";

 for (int i = 0; i < byteArray.length; i++) {

  strDigest += byteToHexStr(byteArray[i]);

 }

 return strDigest;

 }

 

 /**

 * 將字節轉換爲十六進制字符串

 *

 * @param mByte

 * @return

 */

 private static String byteToHexStr(byte mByte) {

 char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

 char[] tempArr = new char[2];

 tempArr[0] = Digit[(mByte >>> 4) & 0X0F];

 tempArr[1] = Digit[mByte & 0X0F];

 String s = new String(tempArr);

 return s;

 }

 public static void sort(String a[]) {

 for (int i = 0; i < a.length - 1; i++) {

  for (int j = i + 1; j < a.length; j++) {

  if (a[j].compareTo(a[i]) < 0) {

   String temp = a[i];

   a[i] = a[j];

   a[j] = temp;

  }

  }

 }

 }

}

二、用戶用戶贊成受權,獲取微信服務器傳過來的倆參數: code、state。其中:

APPID: 微信開發者測試帳號
REDIRECT_URI: 贊成受權後跳轉的 URL

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

/**

 * 第一步:用戶贊成受權,獲取code(引導關注者打開以下頁面:)

 * 獲取 code、state

 */

 public static String getStartURLToGetCode() {

  

 String takenUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";

 takenUrl= takenUrl.replace("APPID", Param.APPID);

 takenUrl= takenUrl.replace("REDIRECT_URI", URL.encode(Param.REDIRECT_URI));

 //FIXME : snsapi_userinfo

 takenUrl= takenUrl.replace("SCOPE", "snsapi_userinfo");

 System.out.println(takenUrl);

 return takenUrl;

 }

三、獲取微信用戶的 access_token、openid

APPID:微信開發者測試帳號
secret:微信開發者測試帳號密碼
code::上一步的 code

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

/**

 * 獲取access_token、openid

 * 第二步:經過code獲取access_token

 * @param code url = "https://api.weixin.qq.com/sns/oauth2/access_token

 *   ?appid=APPID

 *   &secret=SECRET

 *   &code=CODE

 *   &grant_type=authorization_code"

 * */

 public static OAuthInfo getAccess_token(String code){

  

  

 String authUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code ";

 authUrl= authUrl.replace("APPID", Param.APPID);

 authUrl = authUrl.replace("SECRET", Param.SECRET);

 authUrl = authUrl.replace("CODE", code);

 String jsonString = HTTPRequestUtil.sendPost(authUrl,"");

 System.out.println("jsonString: " + jsonString);

 OAuthInfo auth = null;

 try {

  auth = (OAuthInfo) JacksonUtil.parseJSONToObject(OAuthInfo.class, jsonString);

 } catch (Exception e) {

  e.printStackTrace();

 }

 return auth;

 }

四、在數據庫中查詢 openid

我是定義了一個對象 OauthInfo,包括 openid(用戶的標識)屬性。。。

查詢時庫中存在就直接登陸啦,不存在就先去登陸頁,將登陸帳號同 openid 綁定。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

/**

 * 微信引導頁進入的方法

 * @return

 */

 @RequestMapping("/loginByWeiXin")

 public String loginByWeiXin(HttpServletRequest request, Map<String, Object> map) {

 // 微信接口自帶 2 個參數

 String code = request.getParameter("code");

 String state = request.getParameter("state");

 System.out.println("code = " + code + ", state = " + state);

  

 if(code != null && !"".equals(code)) {

  // 受權成功, 微信獲取用戶openID

  OAuthInfo authInfo = WeiXinUtil.getAccess_token(code);

  String openid = authInfo.getOpenid();

  String access_token = authInfo.getAccess_token();

   

  if(access_token == null) {

  // Code 使用過 異常

  System.out.println("Code 使用過 異常.....");

  return "redirect:" + WeiXinUtil.getStartURLToGetCode();

  }

   

  // 數據庫中查詢微信號是否綁定平臺帳號

  SysUser sysUser = weiXinService.getUserByWeiXinID(openid);

  if(sysUser == null) {

  String randomStr = StringUtil.getRandomString(50);

  request.getSession().setAttribute(openid, randomStr);

  // 還沒有綁定帳號

  System.out.println("還沒有綁定帳號.....");

  return "redirect:/index.jsp?openid=" + openid + "&state=" + randomStr;

  }

  userController.doSomeLoginWorkToHomePage(sysUser.getMcid(), map);

  // 登陸成功

  return "homePage";

 }

 // 未受權

 return "redirect:" + WeiXinUtil.getStartURLToGetCode();

  

 }

4、踩過的坑

一、access_token 與普通 access_token。這尼瑪是啥關係?

答:access_token: 登陸受權會獲得一個 access_token, 這個是用於標識登陸用戶(沒有使用次數限制),綁定流程中用的都是 登陸 access_token。

普通 access_token:   調用其它微信應用接口時須要帶上的 access_token,普通 access_token時效爲 2H, 每一個應用天天調用次數<= 2000次。(實際開發時必須加以處理。。我採用的是 quartz 調度^^)

二、uuid、openid。我該綁定uuid?不不不,openid?不不,到底綁哪一個?

答:uuid:微信號綁定後纔有的標識,對於任何應用該微信帳號的 uuid 均相同。同一個微信帳號不一樣的應用 uuid 相同。

  openid:微信號對於每一個應用均有一個不變的 openid,同一個微信帳號不一樣的應用 openid 不一樣。

相關文章
相關標籤/搜索