一、登录流程图
二、微信小程序端
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
|
dologin:function(callback = () =>{}){ let that = this ; wx.login({ success:function(loginres){ if (loginres){ //获取用户信息 wx.getuserinfo({ withcredentials: true , //非必填 默认为true success:function(infores){ console.log(infores, '>>>' ); //请求服务端的登录接口 wx.request({ url: api.loginurl, data:{ code:loginres.code, //临时登录凭证 rawdata:infores.rawdata, //用户非敏感信息 signature:infores.signature, //签名 encryptedata:infores.encrypteddata, //用户敏感信息 iv:infores.iv //解密算法的向量 }, success:function(res){ console.log( 'login success' ); res = res.data; if (res.result== 0 ){ that.globaldata.userinfo = res.userinfo; wx.setstoragesync( 'userinfo' ,json.stringify(res.userinfo)); wx.setstoragesync( 'loginflag' ,res.skey); console.log( "skey=" +res.skey); callback(); } else { that.showinfo( 'res.errmsg' ); } }, fail:function(error){ //调用服务端登录接口失败 // that.showinfo('调用接口失败'); console.log(error); } }); } }); } else { } } }); } |
微信小程序端发起登录请求,携带的参数主要有:
1
2
3
4
5
|
code:loginres.code, //临时登录凭证 rawdata:infores.rawdata, //用户非敏感信息 signature:infores.signature, //签名 encryptedata:infores.encrypteddata, //用户敏感信息 iv:infores.iv //解密算法的向量 |
需要的数据主要有:
result、userinfo和skey
result用来判断是否登录成功,userinfo是用户的一些信息,保存在缓存中,不用每次都从后台获取,skey是用户登录态标识,也放在缓存中,如果skey存在就直接登录,维护用户的登录状态,具有时效性
三、java后台
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
81
82
83
84
85
86
|
@responsebody @requestmapping ( "/login" ) public map<string,object> dologin(model model, @requestparam (value = "code" ,required = false ) string code, @requestparam (value = "rawdata" ,required = false ) string rawdata, @requestparam (value = "signature" ,required = false ) string signature, @requestparam (value = "encryptedata" ,required = false ) string encryptedata, @requestparam (value = "iv" ,required = false ) string iv){ log.info( "start get sessionkey" ); map<string,object> map = new hashmap<string, object>( ); system.out.println( "用户非敏感信息" +rawdata); jsonobject rawdatajson = json.parseobject( rawdata ); system.out.println( "签名" +signature); jsonobject sessionkeyopenid = getsessionkeyoropenid( code ); system.out.println( "post请求获取的sessionandopenid=" +sessionkeyopenid); string openid = sessionkeyopenid.getstring( "openid" ); string sessionkey = sessionkeyopenid.getstring( "session_key" ); system.out.println( "openid=" +openid+ ",session_key=" +sessionkey); user user = userservice.findbyopenid( openid ); //uuid生成唯一key string skey = uuid.randomuuid().tostring(); if (user== null ){ //入库 string nickname = rawdatajson.getstring( "nickname" ); string avatarurl = rawdatajson.getstring( "avatarurl" ); string gender = rawdatajson.getstring( "gender" ); string city = rawdatajson.getstring( "city" ); string country = rawdatajson.getstring( "country" ); string province = rawdatajson.getstring( "province" ); user = new user(); user.setuid( openid ); user.setcreatetime( new date( ) ); user.setsessionkey( sessionkey ); user.setubalance( 0 ); user.setskey( skey ); user.setuaddress( country+ " " +province+ " " +city ); user.setuavatar( avatarurl ); user.setugender( integer.parseint( gender ) ); user.setuname( nickname ); user.setupdatetime( new date( ) ); userservice.insert( user ); } else { //已存在 log.info( "用户openid已存在,不需要插入" ); } //根据openid查询skey是否存在 string skey_redis = (string) redistemplate.opsforvalue().get( openid ); if (stringutils.isnotblank( skey_redis )){ //存在 删除 skey 重新生成skey 将skey返回 redistemplate.delete( skey_redis ); } // 缓存一份新的 jsonobject sessionobj = new jsonobject( ); sessionobj.put( "openid" ,openid ); sessionobj.put( "sessionkey" ,sessionkey ); redistemplate.opsforvalue().set( skey,sessionobj.tojsonstring() ); redistemplate.opsforvalue().set( openid,skey ); //把新的sessionkey和oppenid返回给小程序 map.put( "skey" ,skey ); map.put( "result" , "0" ); jsonobject userinfo = getuserinfo( encryptedata, sessionkey, iv ); system.out.println( "根据解密算法获取的userinfo=" +userinfo); userinfo.put( "balance" ,user.getubalance() ); map.put( "userinfo" ,userinfo ); return map; } |
获取openid和sessionkey方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public static jsonobject getsessionkeyoropenid(string code){ //微信端登录code string wxcode = code; string requesturl = "https://api.weixin.qq.com/sns/jscode2session" ; map<string,string> requesturlparam = new hashmap<string, string>( ); requesturlparam.put( "appid" , "你的小程序appid" ); //小程序appid requesturlparam.put( "secret" , "你的小程序appsecret" ); requesturlparam.put( "js_code" ,wxcode ); //小程序端返回的code requesturlparam.put( "grant_type" , "authorization_code" ); //默认参数 //发送post请求读取调用微信接口获取openid用户唯一标识 jsonobject jsonobject = json.parseobject( urlutil.sendpost( requesturl,requesturlparam )); return jsonobject; } |
解密用户敏感数据获取用户信息
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
|
public static jsonobject getuserinfo(string encrypteddata,string sessionkey,string iv){ // 被加密的数据 byte [] databyte = base64.decode(encrypteddata); // 加密秘钥 byte [] keybyte = base64.decode(sessionkey); // 偏移量 byte [] ivbyte = base64.decode(iv); try { // 如果密钥不足16位,那么就补足. 这个if 中的内容很重要 int base = 16 ; if (keybyte.length % base != 0 ) { int groups = keybyte.length / base + (keybyte.length % base != 0 ? 1 : 0 ); byte [] temp = new byte [groups * base]; arrays.fill(temp, ( byte ) 0 ); system.arraycopy(keybyte, 0 , temp, 0 , keybyte.length); keybyte = temp; } // 初始化 security.addprovider( new bouncycastleprovider()); cipher cipher = cipher.getinstance( "aes/cbc/pkcs7padding" , "bc" ); secretkeyspec spec = new secretkeyspec(keybyte, "aes" ); algorithmparameters parameters = algorithmparameters.getinstance( "aes" ); parameters.init( new ivparameterspec(ivbyte)); cipher.init( cipher.decrypt_mode, spec, parameters); // 初始化 byte [] resultbyte = cipher.dofinal(databyte); if ( null != resultbyte && resultbyte.length > 0 ) { string result = new string(resultbyte, "utf-8" ); return json.parseobject(result); } } catch (nosuchalgorithmexception e) { log.error(e.getmessage(), e); } catch (nosuchpaddingexception e) { log.error(e.getmessage(), e); } catch (invalidparameterspecexception e) { log.error(e.getmessage(), e); } catch (illegalblocksizeexception e) { log.error(e.getmessage(), e); } catch (badpaddingexception e) { log.error(e.getmessage(), e); } catch (unsupportedencodingexception e) { log.error(e.getmessage(), e); } catch (invalidkeyexception e) { log.error(e.getmessage(), e); } catch (invalidalgorithmparameterexception e) { log.error(e.getmessage(), e); } catch (nosuchproviderexception e) { log.error(e.getmessage(), e); } return null ; } |
四、流程
1.小程序端发起请求并携带主要参数
2.java后台接到/login请求后,根据code去调用微信接口获取用户唯一标识openid和sessionkey
3.根据openid查询mysql数据库,判断该用户是否存在,如果不存在将用户非敏感信息和其他初始化数据存入到数据库中,如果已存在,不操作
4.根据openid查询redis数据库,判断openid对应的skey是否存在,如果存在则删除原来老的skey以及对应的openid和sessionkey
5.通过uuid生成唯一的skey,用openid做键,skey做值,存入到redis中
6.然后把skey做键,openid和sessionkey的json串做值也重新存入到redis中
7.根据解密算法,参数有encrypteddata、sessionkey和iv,获取用户信息userinfo,如果userinfo字段不满足需要,可通过userinfo.put( “balance”,user.getubalance() );添加所需要的字段和值
8.将微信小程序需要的数据封装到map中,返回给小程序端
1
2
3
4
|
map.put( "skey" ,skey ); map.put( "result" , "0" ); map.put( "userinfo" ,userinfo ); return map; |
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/qq_38977097/article/details/80778105