# 登录回调处理
## Handler
```go
package auth
import (
"fmt"
"html/template"
"net/http"
"backend/internal/logic/auth"
"backend/internal/svc"
"backend/internal/types"
"github.com/zeromicro/go-zero/rest/httpx"
)
const callbackHTMLTemplate = `
DevOps 登录回调
{{if .Success}}
用户信息
用户名
{{.User.Username}}
邮箱
{{.User.Email}}
用户ID
{{.User.Id}}
访问令牌 (Token)
{{.Token}}
已复制到剪贴板!
{{else}}
{{end}}
`
type CallbackPageData struct {
Success bool
Token string
User *types.UserInfo
Error string
}
func CallbackHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.CallbackReq
if err := httpx.Parse(r, &req); err != nil {
renderCallbackPage(w, false, "", nil, err.Error())
return
}
l := auth.NewCallbackLogic(r.Context(), svcCtx)
resp, err := l.Callback(&req)
if err != nil {
renderCallbackPage(w, false, "", nil, err.Error())
return
}
renderCallbackPage(w, true, resp.Token, &resp.User, "")
}
}
func renderCallbackPage(w http.ResponseWriter, success bool, token string, user *types.UserInfo, errMsg string) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
data := CallbackPageData{
Success: success,
Token: token,
User: user,
Error: errMsg,
}
tmpl, _ := template.New("callback").Parse(callbackHTMLTemplate)
tmpl.Execute(w, data)
}
```
## Logic
```go
package auth
import (
"backend/internal/svc"
"backend/internal/types"
"backend/model"
"context"
"time"
"github.com/casdoor/casdoor-go-sdk/casdoorsdk"
"gorm.io/gorm"
)
type CallbackLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewCallbackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CallbackLogic {
return &CallbackLogic{ctx: ctx, svcCtx: svcCtx}
}
func (l *CallbackLogic) Callback(req *types.CallbackReq) (*types.CallbackResp, error) {
// 换取 Casdoor Token
authConfig, err := l.svcCtx.Casdoor.ExchangeToken(req.Code)
if err != nil {
return nil, err
}
casdoorUser := authConfig.Claims.User
// 查找或创建本地用户
user, err := l.findOrCreateUser(casdoorUser)
if err != nil {
return nil, err
}
// 生成本地 JWT
token, expiresAt, _ := l.svcCtx.JWT.GenerateToken(user.ID, user.Username, user.Email)
return &types.CallbackResp{
Token: token,
ExpiresAt: expiresAt,
User: types.UserInfo{
Id: user.ID,
Username: user.Username,
Email: user.Email,
Status: user.Status,
},
}, nil
}
func (l *CallbackLogic) findOrCreateUser(casdoorUser *casdoorsdk.User) (*model.User, error) {
var user model.User
// 用用户名查询
err := l.svcCtx.DB.Where("username = ?", casdoorUser.Name).First(&user).Error
if err == nil {
return &user, nil
}
if err != gorm.ErrRecordNotFound {
return nil, err
}
// 自动创建新用户
user = model.User{
UserType: "casdoor",
Username: casdoorUser.Name,
Email: casdoorUser.Email,
Avatar: casdoorUser.Avatar,
Role: "member",
Status: 1,
CreatedAt: time.Now(),
}
l.svcCtx.DB.Create(&user)
return &user, nil
}
```