- 客户端使用用户名跟密码请求登录
- 服务端收到请求,去验证用户名与密码
- 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
- 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
- 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
- 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
1、Token的引入:Token是在客户端频繁向服务端请求数据,服务端频繁的去数据库查询用户名和密码并进行对比,判断用户名和密码正确与否,并作出相应提示,在这样的背景下,Token便应运而生。
2、Token的定义:Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。
3、使用Token的目的:Token的目的是为了减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮。
二、如何使用Token?
1、用设备号/设备mac地址作为Token(推荐)
客户端:客户端在登录的时候获取设备的设备号/mac地址,并将其作为参数传递到服务端。
服务端:服务端接收到该参数后,便用一个变量来接收同时将其作为Token保存在数据库,并将该Token设置到session中,客户端每次请求的时候都要统一拦截,并将客户端传递的token和服务器端session中的token进行对比,如果相同则放行,不同则拒绝。
分析:此刻客户端和服务器端就统一了一个唯一的标识Token,而且保证了每一个设备拥有了一个唯一的会话。该方法的缺点是客户端需要带设备号/mac地址作为参数传递,而且服务器端还需要保存;优点是客户端不需重新登录,只要登录一次以后一直可以使用,至于超时的问题是有服务器这边来处理,如何处理?若服务器的Token超时后,服务器只需将客户端传递的Token向数据库中查询,同时并赋值给变量Token,如此,Token的超时又重新计时。
2、用session值作为Token
客户端:客户端只需携带用户名和密码登陆即可。
客户端:客户端接收到用户名和密码后并判断,如果正确了就将本地获取sessionID作为Token返回给客户端,客户端以后只需带上请求数据即可。
分析:这种方式使用的好处是方便,不用存储数据,但是缺点就是当session过期后,客户端必须重新登录才能进行访问数据。
三、使用过程中出现的问题以及解决方案?
刚才我们轻松介绍了Token的两种使用方式,但是在使用过程中我们还出现各种问题,Token第一种方法中我们隐藏了一个在网络不好或者并发请求时会导致多次重复提交数据的问题?
>>>>>>>>>>>>>>
setInterval(function(){ $(".login_Btn").click() }, 1000);
微信:小程序
appId(应用唯一标识,在微信开放平台提交应用审核通过后获得)
secret(应用密钥AppSecret,在微信开放平台提交应用审核通过后获得)
code
grant_type(authorization_code)参数
=================================================
小程序登录登录凭证校验
https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
openid | string | 用户唯一标识 |
session_key | string | 会话密钥 |
unionid | string | 用户在开放平台的唯一标识符,在满足 UnionID 下发条件的情况下会返回,详见 UnionID 机制说明。 |
errcode | number | 错误码 |
errmsg | string | 错误信息 |
e:->jwt
$wx=[
'openid'=>'onbAZ4xqJjYPtPCz-O6DWmHN7EpA',
'uniqid'=>'o9VTO0rrZOrGk6BTJOYicrJmIpIk',
'session_key'=>'tiihtNczf5v6AKRyjwEUhQ=='
];
$base_header=eyJhbGdvcml0aG0iOiJTSEEyNTYiLCJ0eXBlIjoiSldUIn0
set Array
(
[algorithm] => SHA256
[type] => JWT
)
$payload:
Array
(
[issuer] => StockSmallProcedure
[issue_time] => 1556175091
[expire_time] => 1558767091
[uniqid] => a026700d9bb2d712d7bb98b406d6ec04 //md5(uniqid('JWT') . time()), //唯一标识
[uid] => 6
[session_key] => tiihtNczf5v6AKRyjwEUhQ==
)
=>base64Encode($payload)
$base_payload=eyJpc3N1ZXIiOiJTdG9ja1NtYWxsUHJvY2VkdXJlIiwiaXNzdWVfdGltZSI6MTU1NjE3NTA5MSwiZXhwaXJlX3RpbWUiOjE1NTg3NjcwOTEsInVuaXFpZCI6ImEwMjY3MDBkOWJiMmQ3MTJkN2JiOThiNDA2ZDZlYzA0IiwidWlkIjoxNCwic2Vzc2lvbl9rZXkiOiJ0aWlodE5jemY1djZBS1J5andFVWhRPT0ifQ
=>set_signature($payload):base64Encode(hash_hmac('sha256', json_encode($params), config('applet.app_secret')))
$base_sign: IjdjNGQ0N2YzODhiNWYzY2RhZmU5ZjU5ODY3NjYyZjRmYWU4NzBhODVmNzM0YWZiODYyMzgzN2ZmZDNkOTg1Mzgi
token=join('.', [$base_header, $base_payload, $base_sign])
='eyJhbGdvcml0aG0iOiJTSEEyNTYiLCJ0eXBlIjoiSldUIn0.eyJpc3N1ZXIiOiJTdG9ja1NtYWxsUHJvY2VkdXJlIiwiaXNzdWVfdGltZSI6MTU1NzM5MTAwNiwiZXhwaXJlX3RpbWUiOjE1NTk5ODMwMDYsInVuaXFpZCI6ImViYjBjNWM5MDVhZjFkNjY1MDhkZWM4ODU5ODQ2YWQ2IiwidWlkIjo2LCJzZXNzaW9uX2tleSI6InRpaWh0TmN6ZjV2NkFLUnlqd0VVaFE9PSJ9.Ijg1ODFkNzJmNzgzMGYyZGU1OTk4NjAyOWFhM2NhY2JmYzk0ZjJmMGIwYzYwZTZjZmQ4ZDg5YzU0NGYzYWM0Mjki'
=================================================
/**
* 验证token
*/
public function veriftJwt($data = '')
{
if (!$data) return false;
if (substr_count($data, '.') < 2)
return false;
//拆分数据s
list($header, $payload, $sign) = explode('.', $data);
//验证三个参数
if (!$header || !$payload || !$sign) return false;
//验证头部信息
$header = self::base64Decode($header);
if (!$header['algorithm']) return false;
$payload = self::base64Decode($payload);
//验证签名
$resultSign = self::set_signature($payload);
if ($resultSign != $sign)
return false;
//验证签发时间大于服务器时间s
if ($payload['issue_time'] && $payload['issue_time'] > time())
return false;
//验证过期时间
if ($payload['expire_time'] && $payload['expire_time'] < time())
return false;
return $payload;
}
// db 验证
=>
Array
(
[id] => 6
[applet_openid] => **************
[public_openid] => **************
[nickname] => 脚步
[unionid] => ***************
[avatarUrl] => img
[session_key] => ************
)
===================================================================
微信小程序与微信公众号同一用户登录:
微信小程序得到openid,然后通过openID得到用户的唯一标识,用户得以登录,
然而,当我们调用微信公众号也同样的到openid,同一用户两个不同的openid,不能区分是否为同一用户,
然后发现无论调用微信小程序还是微信公众号同一个用户的到unionid是相同的,所以我们就用unionid来区分是否为同一用户。
全局Access Token
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
{
"access_token": "NU7Kr6v9L9TQaqm5NE3OTPctTZx797Wxw4Snd2WL2HHBqLCiXlDVOw2l-Se0I-WmOLLniAYLAwzhbYhXNjbLc_KAA092cxkmpj5FpuqNO0IL7bB0Exz5s5qC9Umypy-rz2y441W9qgfnmNtIZWSjSQ",
"expires_in": 7200
}
网页授权access_token和普通access_token的区别
1、微信网页授权是通过OAuth2.0机制实现的,在用户授权给公众号后,公众号可以获取到一个网页授权特有的接口调用凭证(网页授权access_token),通过网页授权access_token可以进行授权后接口调用,如获取用户基本信息;
2、其他微信接口,需要通过基础支持中的“获取access_token”接口来获取到的普通access_token调用。
用户管理-公众号获取用户基本信息(UnionID机制)
https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID
{
"subscribe": 1,
"openid": "o6_bmjrPTlm6_2sgVt7hMZOPfL2M",
"nickname": "Band",
"sex": 1,
"language": "zh_CN",
"city": "广州",
"province": "广东",
"country": "中国",
"headimgurl":"http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
"subscribe_time": 1382694957,
"unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
"remark": "",
"groupid": 0,
"tagid_list":[128,2],
"subscribe_scene": "ADD_SCENE_QR_CODE",
"qr_scene": 98765,
"qr_scene_str": ""
}
网页授权
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE
2 第二步:通过code换取网页授权access_token
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN", // 参数code是一次性的参数,需要重新获取,而重新获取就需要用户再一次登录才能获取code
"openid":"OPENID",
"scope":"SCOPE"
}
https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE"
}
4 第四步:拉取用户信息(需scope为 snsapi_userinfo)
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
{
"openid":" OPENID",
" nickname": NICKNAME,
"sex":"1",
"province":"PROVINCE"
"city":"CITY",
"country":"COUNTRY",
"headimgurl": "http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
"privilege":[ "PRIVILEGE1" "PRIVILEGE2" ],
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
https://api.weixin.qq.com/sns/auth?access_token=ACCESS_TOKEN&openid=OPENID
{ "errcode":0,"errmsg":"ok"}
==================================================================
网页开发:微信JS-SDK说明文档
微信JS-SDK是微信公众平台 面向网页开发者提供的基于微信内的网页开发工具包。
通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信分享、扫一扫、卡券、支付等微信特有的能力,为微信用户提供更优质的网页体验。
GET:https://api.weixin.qq.com/cgi-bin/ticket/getticket
jsapi_ticket是公众号用于调用微信JS接口的临时票据