Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
catmes
EasyIM
提交
9642de24
E
EasyIM
项目概览
catmes
/
EasyIM
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
E
EasyIM
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
9642de24
编写于
2月 28, 2023
作者:
W
wuhanqing
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
ADD API CheckUserToken, RefreshUserToken
上级
cbc6757c
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
233 addition
and
49 deletion
+233
-49
database/user.go
database/user.go
+106
-18
model/response.go
model/response.go
+7
-7
server/handler/http.go
server/handler/http.go
+120
-24
未找到文件。
database/user.go
浏览文件 @
9642de24
...
...
@@ -36,30 +36,74 @@ func GetDefaultAvatar() string {
return
"https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png"
}
func
(
u
User
)
getJwt
(
expiresin
int
)
string
{
jwt
:=
miniutils
.
NewJwt
(
u
.
Salt
)
info
:=
map
[
string
]
interface
{}{
"id"
:
u
.
ID
,
"account"
:
u
.
Account
,
"avatar"
:
u
.
Avatar
,
func
(
u
User
)
Logout
(
token
string
)
error
{
claims
,
err
:=
u
.
CheckTokenGrantType
(
token
,
ACCESS_TOKEN
)
if
err
!=
nil
{
return
err
}
u
,
err
=
u
.
GetUserByJwt
(
token
,
claims
)
if
err
!=
nil
{
return
err
}
return
u
.
UpdateSalt
()
}
func
(
u
*
User
)
UpdateSalt
()
error
{
u
.
ResetSalt
()
_
,
err
:=
UpdateModel
(
u
,
map
[
string
]
interface
{}{
"salt"
:
u
.
Salt
})
return
err
}
func
(
u
User
)
CheckTokenGrantType
(
token
string
,
match
string
)
(
claims
map
[
string
]
interface
{},
err
error
)
{
claims
,
err
=
u
.
DecodeJwt
(
token
)
if
err
!=
nil
{
return
}
grantType
,
ok
:=
claims
[
GRANT_TYPE
]
if
!
ok
{
err
=
fmt
.
Errorf
(
"grant_type not found in token claims"
)
return
}
if
grantType
.
(
string
)
!=
match
{
err
=
fmt
.
Errorf
(
"the token must be "
+
match
)
}
return
}
func
(
u
User
)
getJwt
(
expiresin
int
,
info
map
[
string
]
interface
{})
string
{
jwt
:=
miniutils
.
NewJwt
(
u
.
Salt
)
token
,
_
:=
jwt
.
Create
(
info
,
time
.
Second
*
time
.
Duration
(
expiresin
))
return
token
}
func
(
u
User
)
GetUserByJwt
(
jwtStr
string
)
(
user
User
,
err
error
)
{
var
segInfo
map
[
string
]
interface
{}
func
(
u
User
)
DecodeJwt
(
jwtToken
string
)
(
map
[
string
]
interface
{},
error
)
{
jwt
:=
miniutils
.
NewJwt
(
""
)
segInfo
,
err
=
jwt
.
Decode
(
jwtStr
)
return
jwt
.
Decode
(
jwtToken
)
}
// GetUserByJwt 根据JWT字符串获取用户对象。
// claims 可以为 nill
func
(
u
User
)
GetUserByJwt
(
jwtStr
string
,
claims
map
[
string
]
interface
{})
(
user
User
,
err
error
)
{
if
claims
==
nil
{
claims
,
err
=
u
.
DecodeJwt
(
jwtStr
)
if
err
!=
nil
{
return
}
}
jsUid
:=
claims
[
"id"
]
.
(
json
.
Number
)
var
uid
int64
uid
,
err
=
jsUid
.
Int64
()
if
err
!=
nil
{
return
}
jsUid
:=
segInfo
[
"id"
]
.
(
json
.
Number
)
uid
,
_
:=
jsUid
.
Int64
()
user
.
ID
=
uid
GetModel
(
&
user
)
// user.Department, user.Position empty
log
.
Println
(
"---FoundUser--By--Jwt---user.Salt------"
,
user
.
Salt
)
jwt
=
miniutils
.
NewJwt
(
user
.
Salt
)
if
user
.
Account
==
""
{
err
=
fmt
.
Errorf
(
"user not found"
)
user
=
User
{}
return
}
jwt
:=
miniutils
.
NewJwt
(
user
.
Salt
)
_
,
err
=
jwt
.
Parse
(
jwtStr
)
if
err
!=
nil
{
log
.
Println
(
"--GetUserByJwt--Error:"
,
err
)
...
...
@@ -67,13 +111,45 @@ func (u User) GetUserByJwt(jwtStr string) (user User, err error) {
return
}
const
(
ACCESS_TOKEN
=
"access_token"
REFRESH_TOKEN
=
"refresh_token"
GRANT_TYPE
=
"grant_type"
)
func
(
u
User
)
GetTokenExpiresIn
(
grantType
string
)
int
{
if
grantType
==
ACCESS_TOKEN
{
return
7200
// 有效期 2 小时
}
if
grantType
==
REFRESH_TOKEN
{
return
2592000
// 有效期 30 天. 超长有效期的refresh_token有效防止泄露用户密码
}
return
0
}
func
(
u
User
)
GetAccessToken
()
string
{
tokenInfo
:=
map
[
string
]
interface
{}{
"id"
:
u
.
ID
,
"account"
:
u
.
Account
,
GRANT_TYPE
:
ACCESS_TOKEN
,
}
return
u
.
getJwt
(
u
.
GetTokenExpiresIn
(
ACCESS_TOKEN
),
tokenInfo
)
}
func
(
u
User
)
GetRefreshToken
()
string
{
refreshInfo
:=
map
[
string
]
interface
{}{
"id"
:
u
.
ID
,
"account"
:
u
.
Account
,
GRANT_TYPE
:
REFRESH_TOKEN
,
}
return
u
.
getJwt
(
u
.
GetTokenExpiresIn
(
REFRESH_TOKEN
),
refreshInfo
)
}
func
(
u
User
)
GetJwtInfo
()
JwtInfo
{
expiresin
:=
7200
// 有效期 2 小时
refreshExpiresin
:=
2592000
// 有效期 30 天. 超长有效期的refresh_token有效防止泄露用户密码
return
JwtInfo
{
AccessToken
:
u
.
getJwt
(
expiresin
),
RefreshToken
:
u
.
getJwt
(
refreshExpiresin
),
Expiresin
:
expiresin
,
AccessToken
:
u
.
GetAccessToken
(
),
RefreshToken
:
u
.
GetRefreshToken
(
),
Expiresin
:
u
.
GetTokenExpiresIn
(
ACCESS_TOKEN
)
,
}
}
...
...
@@ -108,6 +184,18 @@ func (u User) Register(password string) (User, error) {
if
u
.
Account
==
""
&&
u
.
Mobile
==
""
{
return
User
{},
fmt
.
Errorf
(
"登录账号不能为空"
)
}
if
u
.
Account
==
""
{
u
.
Account
=
u
.
Mobile
}
if
u
.
Mobile
==
""
{
u
.
Mobile
=
u
.
Account
}
if
u
.
Email
==
""
{
u
.
Email
=
u
.
Account
+
"@example.com"
}
if
u
.
Avatar
==
""
{
u
.
Avatar
=
GetDefaultAvatar
()
}
user
.
Account
=
u
.
Account
user
.
Mobile
=
u
.
Mobile
user
.
Avatar
=
u
.
Avatar
...
...
model/response.go
浏览文件 @
9642de24
...
...
@@ -28,13 +28,13 @@ func (r Response) getHeader() []string {
fmt
.
Sprintf
(
"Content-Length: %d"
,
bodyLen
),
"Connection: close"
,
// Connection: keep-alive
"Server: easyim"
,
//
//
ALLOW CORS START
//
"Access-Control-Allow-Credentials: true",
//
"Access-Control-Allow-Headers: Origin, Content-Length, Content-Type, Accept, Token, Auth-Token, X-Requested-With",
//
"Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE, UPDATE",
//
"Access-Control-Allow-Origin: *",
//
"Access-Control-Expose-Headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type",
//
//
ALLOW CORS END
// ALLOW CORS START
"Access-Control-Allow-Credentials: true"
,
"Access-Control-Allow-Headers: Origin, Content-Length, Content-Type, Accept, Token, Auth-Token, X-Requested-With"
,
"Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE, UPDATE"
,
"Access-Control-Allow-Origin: *"
,
"Access-Control-Expose-Headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type"
,
// ALLOW CORS END
// "Keep-Alive: timeout=4",
// "Date: Wed, 22 Feb 2023 09:58:51 GMT",
}
...
...
server/handler/http.go
浏览文件 @
9642de24
...
...
@@ -2,6 +2,9 @@ package handler
import
(
"fmt"
"time"
"encoding/json"
"github.com/iotames/easyim/database"
"github.com/iotames/easyim/model"
...
...
@@ -11,8 +14,8 @@ var HttpApiRoute map[string]func(req *model.Request) error = map[string]func(req
"/api/user/register"
:
userRegister
,
"/api/user/login"
:
userLogin
,
"/api/user/logout"
:
userLogout
,
"/api/user/
access_token"
:
getUserAccess
Token
,
"/api/user/refresh_token"
:
getU
serRefreshToken
,
"/api/user/
check_token"
:
checkUser
Token
,
"/api/user/refresh_token"
:
u
serRefreshToken
,
}
func
HttpHandler
(
req
*
model
.
Request
)
error
{
...
...
@@ -21,7 +24,7 @@ func HttpHandler(req *model.Request) error {
if
ok
{
return
handler
(
req
)
}
data
:=
m
ap
[
string
]
interface
{}
{
data
:=
m
odel
.
JsonObject
{
"protocol"
:
hreq
.
Proto
,
"method"
:
hreq
.
Method
,
"host"
:
hreq
.
Host
,
...
...
@@ -52,7 +55,7 @@ type UserRegisterForm struct {
/**
* @api {post} /api/user/register 用户注册
* @apiName 用户注册接口
* @apiGroup
注册登录
* @apiGroup
用户相关
* @apiUse LoginParams
* @apiBody {String} nickname 用户昵称
* @apiUse PublicCommonParams
...
...
@@ -77,7 +80,7 @@ func userRegister(req *model.Request) error {
/**
* @api {post} /api/user/login 用户登录
* @apiName 用户登录
* @apiGroup
注册登录
* @apiGroup
用户相关
* @apiUse LoginParams
* @apiUse PublicCommonParams
* @apiErrorExample {json} 请求异常示例
...
...
@@ -118,7 +121,7 @@ func loginOrRegisterSuccess(u database.User, req model.Request) error {
data
:=
model
.
JsonObject
{
"id"
:
fmt
.
Sprintf
(
"%d"
,
u
.
ID
),
"nickname"
:
u
.
Nickname
,
"avatar"
:
database
.
GetDefaultAvatar
()
,
"avatar"
:
u
.
Avatar
,
"access_token"
:
jwtInfo
.
AccessToken
,
"expires_in"
:
jwtInfo
.
Expiresin
,
"refresh_token"
:
jwtInfo
.
RefreshToken
,
...
...
@@ -126,47 +129,140 @@ func loginOrRegisterSuccess(u database.User, req model.Request) error {
return
model
.
ResponseApi
(
data
,
"success"
,
200
)
.
Write
(
req
)
}
type
UserLogoutData
struct
{
Account
string
`json:"account"`
AccessToken
string
`json:"access_token"`
type
PostToken
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
注册登录
* @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
:=
UserLogoutData
{}
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
{}
u
,
err
=
u
.
GetUserByJwt
(
postData
.
AccessT
oken
)
claims
,
err
:=
u
.
DecodeJwt
(
t
oken
)
if
err
!=
nil
{
return
model
.
ResponseFail
(
err
.
Error
(),
400
)
.
Write
(
*
req
)
}
u
.
ResetSalt
()
_
,
err
=
database
.
UpdateModel
(
&
u
,
map
[
string
]
interface
{}{
"salt"
:
u
.
Salt
})
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
.
Response
ServerError
(
)
.
Write
(
*
req
)
return
model
.
Response
Fail
(
err
.
Error
(),
400
)
.
Write
(
*
req
)
}
return
model
.
ResponseOk
(
"退出登录成功"
)
.
Write
(
*
req
)
}
func
getUserAccessToken
(
req
*
model
.
Request
)
error
{
return
nil
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
)
}
func
getUserRefreshToken
(
req
*
model
.
Request
)
error
{
return
nil
/**
* @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
)
}
/**
...
...
@@ -174,7 +270,7 @@ func getUserRefreshToken(req *model.Request) error {
* @apiSuccess {integer} code 状态码(请求成功为200)
* @apiSuccess {string} msg 请求成功提示信息
* @apiSuccess {Object} data 响应数据
* @api
Success
{integer} code 请求异常状态码
* @api
Error
{integer} code 请求异常状态码
* @apiError {string} msg 请求异常提示信息
*/
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录