一、登录流程图
二、微信小程序端
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