【sduoj】身份认证与获取令牌

2021SC@SDUSC

引言

在上一篇文章中我们提到了如何生成和解析 JWT,接下来我们逐步分析如何去使用它。首先,在我们的系统中,对于每个用户来说,他们的账号和密码是不同的,我们要根据这些信息,来生成一个 Token 令牌,以后进行接口调用的时候,只需要出示令牌即可,不需要重新输入账号密码。

源码分析

在数据定义语言中,app_keyapp_secret是我们的认证信息,而created_oncreated_bymodified_onmodified_bydeleted_onis_del对该行记录的一些描述,这些描述往往适用于大多数表。

create table blog_auth
(
    id          int unsigned auto_increment
        primary key,
    app_key     varchar(20)      default '' null comment 'Key',
    app_secret  varchar(50)      default '' null comment 'Secret',
    created_on  int unsigned     default 0  null comment '创建时间',
    created_by  varchar(100)     default '' null comment '创建人',
    modified_on int unsigned     default 0  null comment '修改时间',
    modified_by varchar(100)     default '' null comment '修改人',
    deleted_on  int unsigned     default 0  null comment '删除时间',
    is_del      tinyint unsigned default 0  null comment '是否删除 0为未删除'
)
    comment '认证管理' charset = utf8mb4;

internal/model下的auto.go中,为该表添加模型结构,在斜引号中json后面的字符串如app_key是变量AppKey所映射的列名。而*Model中包含了一些类似于CreatedBy的通用信息。

type Auth struct {
    
    
	*Model
	AppKey    string `json:"app_key"`
	AppSecret string `json:"app_secret"`
}

AuthGet方法查询了数据库,如果能找到符合条件的记录,则将记录中的第一条保存到变量auth中;如果找不到的话,auth中的值都为零值。

func (a Auth) Get(db *gorm.DB) (Auth, error) {
    
    
	var auth Auth
	db = db.Where(
		"app_key = ? AND app_secret = ? AND is_del = ?",
		a.AppKey,
		a.AppSecret,
		0,
	)
	err := db.First(&auth).Error
	if err != nil && err != gorm.ErrRecordNotFound {
    
    
		return auth, err
	}

	return auth, nil
}

在数据访问层internal/dao下的auto.go文件中,创建Auth结构体对象,并调用它的Get方法,这样可以查看数据库中是否有满足条件的记录。

func (d *Dao) GetAuth(appKey, appSecret string) (model.Auth, error) {
    
    
	auth := model.Auth{
    
    AppKey: appKey, AppSecret: appSecret}
	return auth.Get(d.engine)
}

在业务层internal/service下的auth.go中,AuthRequest规定了请求体的格式,binging中的required表示请求体中该参数不能为空,否则报错。CheckAuth会将参数体中的AppKeyAppSecret传入GetAuth方法中,然后获取验证信息。如果验证成功的话,auth.ID的值会数据库中的记录保持一致;如果记录不存在,那么auth中的属性会是零值,auth.ID的值为 0。

type AuthRequest struct {
    
    
	AppKey    string `form:"app_key" binding:"required"`
	AppSecret string `form:"app_secret" binding:"required"`
}

func (svc *Service) CheckAuth(param *AuthRequest) error {
    
    
	auth, err := svc.dao.GetAuth(param.AppKey, param.AppSecret)
	if err != nil {
    
    
		return err
	}

	if auth.ID > 0 {
    
    
		return nil
	}

	return errors.New("auth info does not exist")
}

internal/routers/api下的auth.go中,我们会看到GetAuth方法大致分为三个部分,第一部分为接口校验,验证前端传来的请求是否符合规范;第二部分是身份验证,从数据库中寻找能满足条件的记录;第三部分是生成一个 Token 令牌,返回给用户。

值得一说的是,参数的绑定和校验是在BindAndValid方法中进行的,如果参数不符合规则的话,就会把错误返回出去。

func GetAuth(c *gin.Context) {
    
    
	param := service.AuthRequest{
    
    }
	response := app.NewResponse(c)
	valid, errs := app.BindAndValid(c, &param)
	if !valid {
    
    
		global.Logger.Errorf("app.BindAndValid errs: %v", errs)
		errRsp := errcode.InvalidParams.WithDetails(errs.Errors()...)
		response.ToErrorResponse(errRsp)
		return
	}

	svc := service.New(c.Request.Context())
	err := svc.CheckAuth(&param)
	if err != nil {
    
    
		global.Logger.Errorf("svc.CheckAuth err: %v", err)
		response.ToErrorResponse(errcode.UnauthorizedAuthNotExist)
		return
	}

	token, err := app.GenerateToken(param.AppKey, param.AppSecret)
	if err != nil {
    
    
		global.Logger.Errorf("app.GenerateToken err: %v", err)
		response.ToErrorResponse(errcode.UnauthorizedTokenGenerate)
		return
	}

	response.ToResponse(gin.H{
    
    
		"token": token,
	})
}

猜你喜欢

转载自blog.csdn.net/weixin_45922876/article/details/120957585