认证和授权
认证是通过账号密码等方式验证用户的身份 授权是用户能访问什么的过程,在认证之后
令牌token
基于令牌实现认证和授权—OAuth2.0 和 JWT
- 无状态,特别适合微服务
- 可以在任何地方生成, 生成和校验解耦
- 细粒度的访问控制
OAuth2.0
适用场景
客户端 需要 安全可控地获取 用户 授权, 访问服务器资源, 如开放api平台,社交联合登录,第三方应用接入等
名词解释
角色(ROLE)
- Resource Owner。 用户实体
- Resource Server。 服务接口
- Client。 SDK客户端
- Authorization Server。 认证和返回token
令牌(TOKENS)
- Access Token。 默认30天过期,client需要定时获取
- Access Token生成可以通过JWT
授权许可(Authorization Grant)
- Client Credentials。 客户端以自己的名义,访问约定好的资源
- Authorization Code
- Implicit Grant
- Resource owner password credentials
流程
- 创建应用,指定应用的权限范围,获取应用的api_key 和 api_secret
- 通过api_key 和 api_secret 向授权服务申请access token(Client Credentials模式)
- 通过access token访问api服务
JWT
- 分布式站点的单点登录场景,通过用户名密码登录后,获取jwt, 后续的接口请求带这个jwt
- 可以作为OAuth2.0的token使用
- 格式:
[header,声明类型和加密算法].[payload,存放数据].[签名,验证身份]
import "github.com/golang-jwt/jwt"
func (l *GenTokenLogic) GenToken(in *appauthrpc_v1.GenTokenReq) (*appauthrpc_v1.GenTokenResp, error) {
nowTime := time.Now()
expireTime := nowTime.Add(time.Duration(l.svcCtx.Config.ExpireIn) * time.Second)
// 携带的数据
claims := &jwt.StandardClaims{
ExpiresAt: expireTime.Unix(),
}
// 指定加密算法
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// 生成
tokenString, err := token.SignedString([]byte(l.svcCtx.Config.TokenSigningKey))
if err != nil {
return nil, err
}
return &appauthrpc_v1.GenTokenResp{
AccessToken: tokenString,
ExpireIn: l.svcCtx.Config.ExpireIn,
}, nil
}
func (l *CheckTokenLogic) CheckToken(in *appauthrpc_v1.CheckTokenReq) (*appauthrpc_v1.CheckTokenResp, error) {
token, err := jwt.Parse(in.AccessToken, func(token *jwt.Token) (interface{}, error) {
return []byte(l.svcCtx.Config.TokenSigningKey), nil
})
if err != nil || token == nil {
return nil, err
}
resp := &appauthrpc_v1.CheckTokenResp{
Ret: RET_OK,
Msg: "ok.",
}
if ve, ok := err.(*jwt.ValidationError); ok {
resp.Ret = RET_VALID_ERR
if ve.Errors&jwt.ValidationErrorMalformed != 0 {
resp.Msg = "not a token."
} else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 {
resp.Msg = "token expired."
} else {
resp.Ret = RET_VALID_UNKNOW
resp.Msg = "invalid token."
}
} else if !token.Valid{
resp.Ret = RET_VALID_UNKNOW
resp.Msg = "invalid token."
}
return resp, nil
}
其它鉴权方式
session-cookie 和 账号密码