第三方网站微信登陆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 不一样。

相关文章
相关标签/搜索