diff --git a/.gitignore b/.gitignore index 8a316eb456c55bb669f341a92e39058a554756e3..465d086e045675ee45ecf98b296d2804d6bdb692 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ runtime/ *.db *.log *.cookie -*.json go.sum .env *.exe diff --git a/apidoc.json b/apidoc.json new file mode 100644 index 0000000000000000000000000000000000000000..26ba369da5e9a0db0d26aed2f37447798e05adc9 --- /dev/null +++ b/apidoc.json @@ -0,0 +1,7 @@ +{ + "name": "EasyIM", + "description": "服务端API接口", + "title": "EasyIM接口文档", + "url" : "http://127.0.0.1:8888", + "sampleUrl": "http://127.0.0.1:8888" +} \ No newline at end of file diff --git a/model/datapack.go b/model/datapack.go index 9ce8f80177224402f54ee32c5933e342b4f56731..59455ea879de060a7477ca48611d985ad554e752 100644 --- a/model/datapack.go +++ b/model/datapack.go @@ -46,7 +46,7 @@ func (dp DataPack) Pack(data protoreflect.ProtoMessage) (result []byte, err erro result, err = proto.Marshal(data) } if dp.protocol == PROTOCOL_WEBSOCKET { - result = WebSocketPackage(result) + result = WebSocketPack(result) } if dp.msgFormat != config.MSG_FORMAT_JSON && dp.msgFormat != config.MSG_FORMAT_PROTOBUF { err = fmt.Errorf("msgFormat(%v) can not Pack.", dp.msgFormat) @@ -56,7 +56,7 @@ func (dp DataPack) Pack(data protoreflect.ProtoMessage) (result []byte, err erro func (dp DataPack) Unpack(data []byte, result protoreflect.ProtoMessage) error { if dp.protocol == PROTOCOL_WEBSOCKET { - data = WebSocketParse(data) + data = WebSocketUnpack(data) } if dp.msgFormat == config.MSG_FORMAT_JSON { return json.Unmarshal(data, result) diff --git a/model/websocket.go b/model/websocket.go index 56046c5ca1e33898098c3be9616d501542595eac..06dc550277b9a15ae93f6ae924308c820abd08b8 100644 --- a/model/websocket.go +++ b/model/websocket.go @@ -10,7 +10,7 @@ func BytesCombine(pBytes ...[]byte) []byte { return bytes.Join(pBytes, []byte("")) } -func WebSocketParse(data []byte) []byte { +func WebSocketUnpack(data []byte) []byte { en_bytes := []byte("") cn_bytes := make([]int, 0) @@ -71,7 +71,7 @@ func WebSocketParse(data []byte) []byte { return en_bytes } -func WebSocketPackage(data []byte) []byte { +func WebSocketPack(data []byte) []byte { lenth := len(data) token := string(0x81) if lenth < 126 { diff --git a/server/handler/http.go b/server/handler/http.go index de9811d84d4ebd0ba37368436d90a0e14a133e0e..48bdf9238ead7992a812618c9bad032b248534c1 100644 --- a/server/handler/http.go +++ b/server/handler/http.go @@ -1,12 +1,6 @@ package handler import ( - "fmt" - "time" - - "encoding/json" - - "github.com/iotames/easyim/database" "github.com/iotames/easyim/model" ) @@ -16,6 +10,11 @@ var HttpApiRoute map[string]func(req *model.Request) error = map[string]func(req "/api/user/logout": userLogout, "/api/user/check_token": checkUserToken, "/api/user/refresh_token": userRefreshToken, + "/api/user/friends": getUserFriends, + "/api/user/friend/add": addUserFriend, + "/api/user/friend/accept": acceptUserFriend, + "/api/user/friend/remove": removeUserFriend, + "/api/user/search": searchUser, } func HttpHandler(req *model.Request) error { @@ -46,230 +45,16 @@ type UserRegisterForm struct { Nickname string `json:"nickname"` } -/** - * @apiDefine LoginParams - * @apiBody {String} account 用户登录账号 - * @apiBody {String} password 用户登录密码 - */ - -/** - * @api {post} /api/user/register 用户注册 - * @apiName 用户注册接口 - * @apiGroup 用户相关 - * @apiUse LoginParams - * @apiBody {String} nickname 用户昵称 - * @apiUse PublicCommonParams - * @apiErrorExample {json} 请求异常示例 - * {"code":400,"msg":"注册失败!登录账号已存在","data":{}} - * @apiUse LoginOrRegisterSuccessBlock - */ -func userRegister(req *model.Request) error { - postData := UserRegisterForm{} - err := req.GetHttpBodyToJson(&postData) - if err != nil { - return req.ResponseJson(model.ResponseQueryArgsError(err.Error())) - } - u := database.User{Account: postData.Account, Nickname: postData.Nickname} - u, err = u.Register(postData.Password) - if err != nil { - return model.ResponseFail(err.Error(), 400).Write(*req) - } - return loginOrRegisterSuccess(u, *req) -} - -/** - * @api {post} /api/user/login 用户登录 - * @apiName 用户登录 - * @apiGroup 用户相关 - * @apiUse LoginParams - * @apiUse PublicCommonParams - * @apiErrorExample {json} 请求异常示例 - * {"code":400,"msg":"密码不正确","data":{}} - * @apiUse LoginOrRegisterSuccessBlock - */ -func userLogin(req *model.Request) error { - postData := UserLoginForm{} - err := req.GetHttpBodyToJson(&postData) - if err != nil { - return req.ResponseJson(model.ResponseQueryArgsError(err.Error())) - } - user := new(database.User) - user.Account = postData.Account - database.GetModel(user) - if user.ID == 0 { - return model.ResponseFail("找不到登录账号", 400).Write(*req) - } - if !user.CheckPassword(postData.Password) { - return model.ResponseFail("密码不正确", 400).Write(*req) - } - return loginOrRegisterSuccess(*user, *req) -} - -/** - * @apiDefine LoginOrRegisterSuccessBlock - * @apiSuccess {String} data.id 用户ID - * @apiSuccess {String} data.nickname 用户昵称 - * @apiSuccess {String} data.avatar 用户头像 - * @apiSuccess {String} data.access_token 通讯凭证,在IM通讯中或需要身份鉴权的API中使用。 有效期7200秒(2小时) - * @apiSuccess {String} data.expires_in access_token(通讯凭证)的有效期(一般为7200秒) - * @apiSuccess {String} data.refresh_token 用于刷新access_token(通讯凭证),有效期30天 - * @apiSuccessExample {json} 请求成功示例 - * {"code":200,"msg":"success","data":{"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50IjoiYWNjb3VudFd1aGFucWluZyIsImF2YXRhciI6IiIsImV4cCI6MTY3NzQ3NDkxNCwiaWQiOjE2Mjk0MjA5MjQ5MTI1Mzc2MDB9.IucceY2x7FSB81-nxEj_yMYggYaBnCzEX1GA8LdzPCE","avatar":"https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png","expires_in":7200,"id":"1629420924912537600","nickname":"飞天的猪","refresh_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50IjoiYWNjb3VudFd1aGFucWluZyIsImF2YXRhciI6IiIsImV4cCI6MTY4MDA1OTcxNCwiaWQiOjE2Mjk0MjA5MjQ5MTI1Mzc2MDB9.Mu4N8-uegCdq26ocIx7HINmoUgLyrwpqo4cYDslHwzs"}} - */ -func loginOrRegisterSuccess(u database.User, req model.Request) error { - jwtInfo := u.GetJwtInfo() - data := model.JsonObject{ - "id": fmt.Sprintf("%d", u.ID), - "nickname": u.Nickname, - "avatar": u.Avatar, - "access_token": jwtInfo.AccessToken, - "expires_in": jwtInfo.Expiresin, - "refresh_token": jwtInfo.RefreshToken, - } - return model.ResponseApi(data, "success", 200).Write(req) +type PostAccessToken struct { + AccessToken string `json:"access_token"` } -type PostToken struct { +type PostRefreshToken struct { ResetSecret bool `json:"reset_secret"` GrantType string `json:"grant_type"` - AccessToken string `json:"access_token"` RefreshToken string `json:"refresh_token"` } -/** - * @api {post} /api/user/logout 退出登录 - * @apiGroup 用户相关 - * @apiBody {String} access_token 通讯凭证 - * @apiUse PublicCommonParams - * @apiErrorExample {json} 请求异常示例 - * {"code":400,"msg":"access_token不正确","data":{}} - * @apiSuccessExample {json} 请求成功示例 - * {"code":200,"msg":"退出登录成功","data":{}} - */ -func userLogout(req *model.Request) error { - postData := PostToken{} - err := req.GetHttpBodyToJson(&postData) - if err != nil { - return req.ResponseJson(model.ResponseQueryArgsError(err.Error())) - } - u := database.User{} - err = u.Logout(postData.AccessToken) - if err != nil { - return model.ResponseFail(err.Error(), 400).Write(*req) - } - return model.ResponseOk("登出成功").Write(*req) -} - -/** -* @api {get} /api/user/check_token 校验token -* @apiGroup 用户相关 -* @apiQuery {String} token 通讯凭证: access_token 或 refresh_token 的值 -* @apiSuccess {integer} code 状态码(请求成功为200) -* @apiSuccess {string} msg 请求成功提示信息 -* @apiSuccess {Object} data 响应数据 -* @apiError {integer} code 请求异常状态码 -* @apiError {string} msg 请求异常提示信息 -* @apiSuccess {Number} data.expires_in 有效期剩余时间。单位:秒 -* @apiSuccess {String} data.grant_type token授权模式。值为 access_token 或 refresh_token -* @apiErrorExample {json} 请求异常示例 -* {"code":400,"msg":"access_token不正确","data":{}} -* @apiSuccessExample {json} 请求成功示例 -* {"code":200,"msg":"success","data":{"expires_in":7130,"grant_type":"access_token"}} - */ -func checkUserToken(req *model.Request) error { - query := req.GetHttpRequest().URL.Query() - token := query.Get("token") - u := database.User{} - claims, err := u.DecodeJwt(token) - if err != nil { - return model.ResponseFail(err.Error(), 400).Write(*req) - } - grantType, ok := claims[database.GRANT_TYPE] - if !ok { - return model.ResponseFail("token 不正确", 400).Write(*req) - } - _, err = u.GetUserByJwt(token, claims) - if err != nil { - return model.ResponseFail(err.Error(), 400).Write(*req) - } - expiredAt, _ := claims["exp"].(json.Number).Int64() - expiresIn := expiredAt - time.Now().Unix() - data := model.JsonObject{ - "grant_type": grantType, - "expires_in": expiresIn, - } - return model.ResponseApi(data, "success", 200).Write(*req) -} - -/** -* @api {post} /api/user/refresh_token 续期token -* @apiGroup 用户相关 -* @apiSuccess {integer} code 状态码(请求成功为200) -* @apiSuccess {string} msg 请求成功提示信息 -* @apiSuccess {Object} data 响应数据 -* @apiError {integer} code 请求异常状态码 -* @apiError {string} msg 请求异常提示信息 -* @apiBody {String} grant_type 作用域. 值为: access_token或refresh_token. 告诉服务器刷新哪个token. -* @apiBody {String} refresh_token 用于刷新access_token或refresh_token -* @apiBody {Boolean} [reset_secret] 是否重置密钥。默认否false. 重置密钥后,此前使用的access_token和refresh_token都会失效。 -* @apiSuccess {Number} data.expires_in 有效期(秒)。从当前时间开始算起。过完失效。 -* @apiSuccess {String} data.grant_type 当前token的授权模式。值为 access_token 或 refresh_token -* @apiSuccess {String} data.token 刷新后的 access_token 或 refresh_token 的值 -* @apiErrorExample {json} 请求异常示例 -* {"code":400,"msg":"token不正确","data":{}} -* @apiSuccessExample {json} 请求成功示例 -*{ -* "code": 200, -* "msg": "success", -* "data": { -* "expires_in": 7200, -* "grant_type": "access_token", -* "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50Ijoid2hxNzgxNjQiLCJleHAiOjE2Nzc1NzYwOTksImdyYW50X3R5cGUiOiJhY2Nlc3NfdG9rZW4iLCJpZCI6MTYzMDM4MTM4ODg5NTA5NjgzMn0.2Tykk-RhXSyy7KoaxqTCEUEOausy3be_QFh-RIY0Lag" -* } -*} - */ -func userRefreshToken(req *model.Request) error { - postData := PostToken{} - err := req.GetHttpBodyToJson(&postData) - if err != nil { - return req.ResponseJson(model.ResponseQueryArgsError(err.Error())) - } - // 验证refresh_token Begin - u := new(database.User) - claims, err := u.CheckTokenGrantType(postData.RefreshToken, database.REFRESH_TOKEN) - if err != nil { - return model.ResponseFail(err.Error(), 400).Write(*req) - } - uu, err := u.GetUserByJwt(postData.RefreshToken, claims) - if err != nil { - return model.ResponseFail(err.Error(), 400).Write(*req) - } - // 验证refresh_token End - if postData.ResetSecret { - // 重置 salt, 使此前颁发的所有token失效 - u = &uu - u.UpdateSalt() - } - data := model.JsonObject{ - "grant_type": postData.GrantType, - "expires_in": uu.GetTokenExpiresIn(postData.GrantType), - } - if postData.GrantType == database.ACCESS_TOKEN { - data["token"] = uu.GetAccessToken() - return model.ResponseApi(data, "success", 200).Write(*req) - } - if postData.GrantType == database.REFRESH_TOKEN { - data["token"] = uu.GetRefreshToken() - return model.ResponseApi(data, "success", 200).Write(*req) - } - return model.ResponseFail("grant_type不正确", 400).Write(*req) -} - -// TODO 我的好友 -// TODO 添加好友 -// TODO 根据用户名搜索用户 -// TODO 删除好友 - /** * @apiDefine PublicCommonParams * @apiSuccess {integer} code 状态码(请求成功为200) diff --git a/server/handler/httpchat.go b/server/handler/httpchat.go new file mode 100644 index 0000000000000000000000000000000000000000..91bd261b9ac42ff4c534167b51ec6d04aac198df --- /dev/null +++ b/server/handler/httpchat.go @@ -0,0 +1,6 @@ +package handler + +// TODO 发起群聊(从好友中选择) +// TODO 邀请好友进群聊 +// TODO 退出群聊 +// TODO 近期聊天 diff --git a/server/handler/httpfriend.go b/server/handler/httpfriend.go new file mode 100644 index 0000000000000000000000000000000000000000..94929d21744e3003502a408218550c091da3b1a0 --- /dev/null +++ b/server/handler/httpfriend.go @@ -0,0 +1,82 @@ +package handler + +import ( + "github.com/iotames/easyim/model" +) + +/** + * @api {get} /api/user/friends 好友列表 + * @apiGroup 好友相关 + * @apiDescription 获取用户的好友列表(通讯录显示的联系人) + * @apiQuery {String} access_token 通讯凭证: access_token 的值 + * @apiSuccess {integer} code 状态码(请求成功为200) + * @apiSuccess {string} msg 请求成功提示信息 + * @apiSuccess {Object} data 响应数据 + * @apiSuccess {Number} daa.total 好友总数 + * @apiSuccess {Object[]} data.items 用户列表 + * @apiSuccess {String} data.items.id 用户ID + * @apiSuccess {String} data.items.account 用户账户名 + * @apiSuccess {String} data.items.nickname 用户昵称 + * @apiSuccess {String} data.items.avatar 用户头像 + * @apiError {integer} code 请求异常状态码 + * @apiError {string} msg 请求异常提示信息 + * @apiErrorExample {json} 请求异常示例 + * {"code":400,"msg":"access_token不正确","data":{}} + * @apiSuccessExample {json} 请求成功示例 + * {"code":200,"msg":"success","data":{}} + */ +func getUserFriends(req *model.Request) error { + return nil +} + +/** + * @api {post} /api/user/friend/add 发起好友邀请 + * @apiName 发起好友邀请 + * @apiGroup 好友相关 + * @apiDescription 搜索用户后,对该用户发送好友邀请。需要用户同意邀请,才能成为正式好友。 + * @apiBody {String} access_token 发起好友邀请的用户的身份令牌 + * @apiBody {String} to_user_id 被邀请用户的ID + * @apiUse PublicCommonParams + * @apiSuccess {String} data.id 本次好友邀请的请求ID + * @apiErrorExample {json} 请求异常示例 + * {"code":400,"msg":"access_token不正确","data":{}} + * @apiSuccessExample {json} 请求成功示例 + * {"code":200,"msg":"success","data":{"id":"1629420924912535555"}} + */ +func addUserFriend(req *model.Request) error { + return nil +} + +/** + * @api {post} /api/user/friend/accept 接受好友邀请 + * @apiGroup 好友相关 + * @apiDescription 同意其他用户发过来的好友申请。正式成为好友。 + * @apiBody {String} access_token 接受好友邀请的用户的身份令牌 + * @apiBody {String} id 好友邀请的请求ID + * @apiUse PublicCommonParams + * @apiErrorExample {json} 请求异常示例 + * {"code":400,"msg":"access_token不正确","data":{}} + * @apiSuccessExample {json} 请求成功示例 + * {"code":200,"msg":"success","data":{}} + */ +func acceptUserFriend(req *model.Request) error { + return nil +} + +/** + * @api {post} /api/user/friend/remove 删除好友 + * @apiGroup 好友相关 + * @apiDescription TODO + */ +func removeUserFriend(req *model.Request) error { + return nil +} + +/** + * @api {get} /api/user/search 用户搜索 + * @apiGroup 好友相关 + * @apiDescription 根据用户账号搜索用户 TODO + */ +func searchUser(req *model.Request) error { + return nil +} diff --git a/server/handler/httpuser.go b/server/handler/httpuser.go new file mode 100644 index 0000000000000000000000000000000000000000..446fb44580b7cd723e913a4c43a53a3023b02043 --- /dev/null +++ b/server/handler/httpuser.go @@ -0,0 +1,223 @@ +package handler + +import ( + "fmt" + "time" + + "encoding/json" + + "github.com/iotames/easyim/database" + "github.com/iotames/easyim/model" +) + +/** + * @apiDefine LoginParams + * @apiBody {String} account 用户登录账号 + * @apiBody {String} password 用户登录密码 + */ + +/** + * @api {post} /api/user/login 用户登录 + * @apiName 用户登录 + * @apiGroup 用户与权限 + * @apiUse LoginParams + * @apiUse PublicCommonParams + * @apiErrorExample {json} 请求异常示例 + * {"code":400,"msg":"密码不正确","data":{}} + * @apiUse LoginOrRegisterSuccessBlock + */ +func userLogin(req *model.Request) error { + postData := UserLoginForm{} + err := req.GetHttpBodyToJson(&postData) + if err != nil { + return req.ResponseJson(model.ResponseQueryArgsError(err.Error())) + } + user := new(database.User) + user.Account = postData.Account + database.GetModel(user) + if user.ID == 0 { + return model.ResponseFail("找不到登录账号", 400).Write(*req) + } + if !user.CheckPassword(postData.Password) { + return model.ResponseFail("密码不正确", 400).Write(*req) + } + return loginOrRegisterSuccess(*user, *req) +} + +/** + * @api {post} /api/user/register 用户注册 + * @apiName 用户注册接口 + * @apiGroup 用户与权限 + * @apiUse LoginParams + * @apiBody {String} nickname 用户昵称 + * @apiUse PublicCommonParams + * @apiErrorExample {json} 请求异常示例 + * {"code":400,"msg":"注册失败!登录账号已存在","data":{}} + * @apiUse LoginOrRegisterSuccessBlock + */ +func userRegister(req *model.Request) error { + postData := UserRegisterForm{} + err := req.GetHttpBodyToJson(&postData) + if err != nil { + return req.ResponseJson(model.ResponseQueryArgsError(err.Error())) + } + u := database.User{Account: postData.Account, Nickname: postData.Nickname} + u, err = u.Register(postData.Password) + if err != nil { + return model.ResponseFail(err.Error(), 400).Write(*req) + } + return loginOrRegisterSuccess(u, *req) +} + +/** + * @apiDefine LoginOrRegisterSuccessBlock + * @apiSuccess {String} data.id 用户ID + * @apiSuccess {String} data.nickname 用户昵称 + * @apiSuccess {String} data.avatar 用户头像 + * @apiSuccess {String} data.access_token 通讯凭证,在IM通讯中或需要身份鉴权的API中使用。 有效期7200秒(2小时) + * @apiSuccess {String} data.expires_in access_token(通讯凭证)的有效期(一般为7200秒) + * @apiSuccess {String} data.refresh_token 用于刷新access_token(通讯凭证),有效期30天 + * @apiSuccessExample {json} 请求成功示例 + * {"code":200,"msg":"success","data":{"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50IjoiYWNjb3VudFd1aGFucWluZyIsImF2YXRhciI6IiIsImV4cCI6MTY3NzQ3NDkxNCwiaWQiOjE2Mjk0MjA5MjQ5MTI1Mzc2MDB9.IucceY2x7FSB81-nxEj_yMYggYaBnCzEX1GA8LdzPCE","avatar":"https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png","expires_in":7200,"id":"1629420924912537600","nickname":"飞天的猪","refresh_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50IjoiYWNjb3VudFd1aGFucWluZyIsImF2YXRhciI6IiIsImV4cCI6MTY4MDA1OTcxNCwiaWQiOjE2Mjk0MjA5MjQ5MTI1Mzc2MDB9.Mu4N8-uegCdq26ocIx7HINmoUgLyrwpqo4cYDslHwzs"}} + */ +func loginOrRegisterSuccess(u database.User, req model.Request) error { + jwtInfo := u.GetJwtInfo() + data := model.JsonObject{ + "id": fmt.Sprintf("%d", u.ID), + "nickname": u.Nickname, + "avatar": u.Avatar, + "access_token": jwtInfo.AccessToken, + "expires_in": jwtInfo.Expiresin, + "refresh_token": jwtInfo.RefreshToken, + } + return model.ResponseApi(data, "success", 200).Write(req) +} + +/** + * @api {post} /api/user/logout 退出登录 + * @apiGroup 用户与权限 + * @apiBody {String} access_token 通讯凭证 + * @apiUse PublicCommonParams + * @apiErrorExample {json} 请求异常示例 + * {"code":400,"msg":"access_token不正确","data":{}} + * @apiSuccessExample {json} 请求成功示例 + * {"code":200,"msg":"退出登录成功","data":{}} + */ +func userLogout(req *model.Request) error { + postData := PostAccessToken{} + err := req.GetHttpBodyToJson(&postData) + if err != nil { + return req.ResponseJson(model.ResponseQueryArgsError(err.Error())) + } + u := database.User{} + err = u.Logout(postData.AccessToken) + if err != nil { + return model.ResponseFail(err.Error(), 400).Write(*req) + } + return model.ResponseOk("登出成功").Write(*req) +} + +/** +* @api {get} /api/user/check_token 校验token +* @apiGroup 用户与权限 +* @apiQuery {String} token 通讯凭证: access_token 或 refresh_token 的值 +* @apiSuccess {integer} code 状态码(请求成功为200) +* @apiSuccess {string} msg 请求成功提示信息 +* @apiSuccess {Object} data 响应数据 +* @apiError {integer} code 请求异常状态码 +* @apiError {string} msg 请求异常提示信息 +* @apiSuccess {Number} data.expires_in 有效期剩余时间。单位:秒 +* @apiSuccess {String} data.grant_type token授权模式。值为 access_token 或 refresh_token +* @apiErrorExample {json} 请求异常示例 +* {"code":400,"msg":"access_token不正确","data":{}} +* @apiSuccessExample {json} 请求成功示例 +* {"code":200,"msg":"success","data":{"expires_in":7130,"grant_type":"access_token"}} + */ +func checkUserToken(req *model.Request) error { + query := req.GetHttpRequest().URL.Query() + token := query.Get("token") + u := database.User{} + claims, err := u.DecodeJwt(token) + if err != nil { + return model.ResponseFail(err.Error(), 400).Write(*req) + } + grantType, ok := claims[database.GRANT_TYPE] + if !ok { + return model.ResponseFail("token 不正确", 400).Write(*req) + } + _, err = u.GetUserByJwt(token, claims) + if err != nil { + return model.ResponseFail(err.Error(), 400).Write(*req) + } + expiredAt, _ := claims["exp"].(json.Number).Int64() + expiresIn := expiredAt - time.Now().Unix() + data := model.JsonObject{ + "grant_type": grantType, + "expires_in": expiresIn, + } + return model.ResponseApi(data, "success", 200).Write(*req) +} + +/** +* @api {post} /api/user/refresh_token 续期token +* @apiGroup 用户与权限 +* @apiSuccess {integer} code 状态码(请求成功为200) +* @apiSuccess {string} msg 请求成功提示信息 +* @apiSuccess {Object} data 响应数据 +* @apiError {integer} code 请求异常状态码 +* @apiError {string} msg 请求异常提示信息 +* @apiBody {String} grant_type 作用域. 值为: access_token或refresh_token. 告诉服务器刷新哪个token. +* @apiBody {String} refresh_token 用于刷新access_token或refresh_token +* @apiBody {Boolean} [reset_secret] 是否重置密钥。默认否false. 重置密钥后,此前使用的access_token和refresh_token都会失效。 +* @apiSuccess {Number} data.expires_in 有效期(秒)。从当前时间开始算起。过完失效。 +* @apiSuccess {String} data.grant_type 当前token的授权模式。值为 access_token 或 refresh_token +* @apiSuccess {String} data.token 刷新后的 access_token 或 refresh_token 的值 +* @apiErrorExample {json} 请求异常示例 +* {"code":400,"msg":"token不正确","data":{}} +* @apiSuccessExample {json} 请求成功示例 +*{ +* "code": 200, +* "msg": "success", +* "data": { +* "expires_in": 7200, +* "grant_type": "access_token", +* "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50Ijoid2hxNzgxNjQiLCJleHAiOjE2Nzc1NzYwOTksImdyYW50X3R5cGUiOiJhY2Nlc3NfdG9rZW4iLCJpZCI6MTYzMDM4MTM4ODg5NTA5NjgzMn0.2Tykk-RhXSyy7KoaxqTCEUEOausy3be_QFh-RIY0Lag" +* } +*} + */ +func userRefreshToken(req *model.Request) error { + postData := PostRefreshToken{} + err := req.GetHttpBodyToJson(&postData) + if err != nil { + return req.ResponseJson(model.ResponseQueryArgsError(err.Error())) + } + // 验证refresh_token Begin + u := new(database.User) + claims, err := u.CheckTokenGrantType(postData.RefreshToken, database.REFRESH_TOKEN) + if err != nil { + return model.ResponseFail(err.Error(), 400).Write(*req) + } + uu, err := u.GetUserByJwt(postData.RefreshToken, claims) + if err != nil { + return model.ResponseFail(err.Error(), 400).Write(*req) + } + // 验证refresh_token End + if postData.ResetSecret { + // 重置 salt, 使此前颁发的所有token失效 + u = &uu + u.UpdateSalt() + } + data := model.JsonObject{ + "grant_type": postData.GrantType, + "expires_in": uu.GetTokenExpiresIn(postData.GrantType), + } + if postData.GrantType == database.ACCESS_TOKEN { + data["token"] = uu.GetAccessToken() + return model.ResponseApi(data, "success", 200).Write(*req) + } + if postData.GrantType == database.REFRESH_TOKEN { + data["token"] = uu.GetRefreshToken() + return model.ResponseApi(data, "success", 200).Write(*req) + } + return model.ResponseFail("grant_type不正确", 400).Write(*req) +}