@@ -20,6 +20,12 @@ type authxHandler struct {
|
||||
// ---- TOTP(JWT 组内) ----
|
||||
|
||||
// totpStatus 返回当前账号两步验证启用状态。
|
||||
//
|
||||
// @Summary 两步验证状态
|
||||
// @Tags 认证
|
||||
// @Success 200 {object} map[string]bool "enabled"
|
||||
// @Security BearerAuth
|
||||
// @Router /api/v1/auth/totp [get]
|
||||
func (h *authxHandler) totpStatus(c *gin.Context) {
|
||||
enabled, err := h.auth.TotpStatus(c.Request.Context(), c.GetString(usernameKey))
|
||||
if err != nil {
|
||||
@@ -30,6 +36,13 @@ func (h *authxHandler) totpStatus(c *gin.Context) {
|
||||
}
|
||||
|
||||
// totpSetup 生成待激活密钥,返回手动输入码与 otpauth URI(前端渲染二维码)。
|
||||
//
|
||||
// @Summary 发起两步验证设置
|
||||
// @Tags 认证
|
||||
// @Success 200 {object} map[string]string "secret 与 otpauthUri"
|
||||
// @Failure 409 {object} map[string]string "已启用"
|
||||
// @Security BearerAuth
|
||||
// @Router /api/v1/auth/totp/setup [post]
|
||||
func (h *authxHandler) totpSetup(c *gin.Context) {
|
||||
secret, uri, err := h.auth.SetupTotp(c.Request.Context(), c.GetString(usernameKey))
|
||||
if err != nil {
|
||||
@@ -44,6 +57,13 @@ func (h *authxHandler) totpSetup(c *gin.Context) {
|
||||
}
|
||||
|
||||
// totpActivate 校验验证码并正式启用两步验证。
|
||||
//
|
||||
// @Summary 激活两步验证
|
||||
// @Tags 认证
|
||||
// @Param body body object true "{code: 6 位验证码}"
|
||||
// @Success 204 "已启用"
|
||||
// @Security BearerAuth
|
||||
// @Router /api/v1/auth/totp/activate [post]
|
||||
func (h *authxHandler) totpActivate(c *gin.Context) {
|
||||
var req struct {
|
||||
Code string `json:"code" binding:"required"`
|
||||
@@ -65,6 +85,13 @@ func (h *authxHandler) totpActivate(c *gin.Context) {
|
||||
}
|
||||
|
||||
// totpDisable 停用两步验证;需当前验证码或登录密码任一确认。
|
||||
//
|
||||
// @Summary 停用两步验证
|
||||
// @Tags 认证
|
||||
// @Param body body object true "{password 或 code 任一确认}"
|
||||
// @Success 204 "已停用"
|
||||
// @Security BearerAuth
|
||||
// @Router /api/v1/auth/totp/disable [post]
|
||||
func (h *authxHandler) totpDisable(c *gin.Context) {
|
||||
var req struct {
|
||||
Password string `json:"password"`
|
||||
@@ -89,6 +116,12 @@ func (h *authxHandler) totpDisable(c *gin.Context) {
|
||||
// ---- 登录凭据(JWT 组内) ----
|
||||
|
||||
// getCredentials 返回登录凭据摘要:当前用户名与密码登录禁用态。
|
||||
//
|
||||
// @Summary 登录凭据摘要
|
||||
// @Tags 认证
|
||||
// @Success 200 {object} map[string]any "username 与 passwordLoginDisabled"
|
||||
// @Security BearerAuth
|
||||
// @Router /api/v1/auth/credentials [get]
|
||||
func (h *authxHandler) getCredentials(c *gin.Context) {
|
||||
disabled, err := h.auth.PasswordLoginDisabled(c.Request.Context())
|
||||
if err != nil {
|
||||
@@ -102,6 +135,14 @@ func (h *authxHandler) getCredentials(c *gin.Context) {
|
||||
}
|
||||
|
||||
// updateCredentials 修改用户名 / 密码;当前密码必验,改名后旧 JWT 随即失效(前端应重新登录)。
|
||||
//
|
||||
// @Summary 修改登录凭据
|
||||
// @Tags 认证
|
||||
// @Param body body service.UpdateCredentialsInput true "新凭据(当前密码必验)"
|
||||
// @Success 204 "已更新,请重新登录"
|
||||
// @Failure 401 {object} map[string]string "当前密码错误"
|
||||
// @Security BearerAuth
|
||||
// @Router /api/v1/auth/credentials [put]
|
||||
func (h *authxHandler) updateCredentials(c *gin.Context) {
|
||||
var req service.UpdateCredentialsInput
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
@@ -125,6 +166,14 @@ func (h *authxHandler) updateCredentials(c *gin.Context) {
|
||||
}
|
||||
|
||||
// updatePasswordLogin 保存密码登录禁用开关;开启需至少绑定一个外部身份。
|
||||
//
|
||||
// @Summary 密码登录开关
|
||||
// @Tags 认证
|
||||
// @Param body body object true "{disabled: bool}"
|
||||
// @Success 204 "已保存"
|
||||
// @Failure 409 {object} map[string]string "未绑定外部身份"
|
||||
// @Security BearerAuth
|
||||
// @Router /api/v1/auth/password-login [put]
|
||||
func (h *authxHandler) updatePasswordLogin(c *gin.Context) {
|
||||
var req struct {
|
||||
Disabled *bool `json:"disabled" binding:"required"`
|
||||
@@ -150,6 +199,11 @@ func (h *authxHandler) updatePasswordLogin(c *gin.Context) {
|
||||
// oauthProviders 返回已配置的 provider 列表(公开,登录页展示按钮),
|
||||
// 并附带密码登录禁用开关:开启且存在可用外部身份时,登录页隐藏密码表单;
|
||||
// provider 清空时不下发禁用,保证界面始终留有登录入口(后端 Login 仍会拒绝)。
|
||||
//
|
||||
// @Summary 外部登录 provider 列表
|
||||
// @Tags 认证
|
||||
// @Success 200 {object} map[string]any "providers 与 passwordLoginDisabled"
|
||||
// @Router /api/v1/auth/oauth/providers [get]
|
||||
func (h *authxHandler) oauthProviders(c *gin.Context) {
|
||||
providers := h.oauth.Providers(c.Request.Context())
|
||||
disabled := false
|
||||
@@ -160,6 +214,13 @@ func (h *authxHandler) oauthProviders(c *gin.Context) {
|
||||
}
|
||||
|
||||
// oauthAuthorize 返回授权跳转 URL;mode=bind 需有效 JWT(绑定到当前账号),login 公开。
|
||||
//
|
||||
// @Summary 外部登录授权跳转
|
||||
// @Tags 认证
|
||||
// @Param provider path string true "oidc / github"
|
||||
// @Param mode query string false "bind=绑定当前账号(需 Bearer),缺省登录"
|
||||
// @Success 200 {object} map[string]string "url"
|
||||
// @Router /api/v1/auth/oauth/{provider}/authorize [get]
|
||||
func (h *authxHandler) oauthAuthorize(c *gin.Context) {
|
||||
provider := c.Param("provider")
|
||||
if provider != "oidc" && provider != "github" {
|
||||
@@ -201,6 +262,14 @@ func (h *authxHandler) bearerUser(c *gin.Context) (string, bool) {
|
||||
}
|
||||
|
||||
// oauthCallback 是 provider 回调落点(浏览器直达):完成登录或绑定后 302 回前端。
|
||||
//
|
||||
// @Summary 外部登录回调
|
||||
// @Tags 认证
|
||||
// @Param provider path string true "oidc / github"
|
||||
// @Param state query string true "授权流程 state"
|
||||
// @Param code query string true "授权码"
|
||||
// @Success 302 "登录 token 经 fragment 回前端,绑定回设置页"
|
||||
// @Router /api/v1/auth/oauth/{provider}/callback [get]
|
||||
func (h *authxHandler) oauthCallback(c *gin.Context) {
|
||||
provider := c.Param("provider")
|
||||
token, _, mode, err := h.oauth.HandleCallback(
|
||||
@@ -233,6 +302,12 @@ func oauthErrText(err error) string {
|
||||
}
|
||||
|
||||
// identities 列出当前账号绑定的外部身份。
|
||||
//
|
||||
// @Summary 已绑定外部身份
|
||||
// @Tags 认证
|
||||
// @Success 200 {object} map[string]any "items"
|
||||
// @Security BearerAuth
|
||||
// @Router /api/v1/auth/identities [get]
|
||||
func (h *authxHandler) identities(c *gin.Context) {
|
||||
items, err := h.oauth.Identities(c.Request.Context(), c.GetString(usernameKey))
|
||||
if err != nil {
|
||||
@@ -243,6 +318,14 @@ func (h *authxHandler) identities(c *gin.Context) {
|
||||
}
|
||||
|
||||
// unbindIdentity 解绑外部身份;密码登录禁用期间不允许解绑最后一个身份。
|
||||
//
|
||||
// @Summary 解绑外部身份
|
||||
// @Tags 认证
|
||||
// @Param id path int true "身份 ID"
|
||||
// @Success 204 "已解绑"
|
||||
// @Failure 409 {object} map[string]string "最后一个身份不可解绑"
|
||||
// @Security BearerAuth
|
||||
// @Router /api/v1/auth/identities/{id} [delete]
|
||||
func (h *authxHandler) unbindIdentity(c *gin.Context) {
|
||||
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
@@ -263,6 +346,12 @@ func (h *authxHandler) unbindIdentity(c *gin.Context) {
|
||||
// ---- OAuth provider 设置(JWT 组内) ----
|
||||
|
||||
// getOAuthSettings 返回 provider 配置(secret 只回设置态)。
|
||||
//
|
||||
// @Summary OAuth provider 配置
|
||||
// @Tags 设置
|
||||
// @Success 200 {object} service.OAuthProvidersView
|
||||
// @Security BearerAuth
|
||||
// @Router /api/v1/settings/oauth [get]
|
||||
func (h *authxHandler) getOAuthSettings(c *gin.Context, settings *service.SettingService) {
|
||||
view, err := settings.OAuthView(c.Request.Context())
|
||||
if err != nil {
|
||||
@@ -273,6 +362,13 @@ func (h *authxHandler) getOAuthSettings(c *gin.Context, settings *service.Settin
|
||||
}
|
||||
|
||||
// updateOAuthSettings 保存 provider 配置;secret 缺省沿用、空串清除。
|
||||
//
|
||||
// @Summary 保存 OAuth provider 配置
|
||||
// @Tags 设置
|
||||
// @Param body body service.UpdateOAuthInput true "provider 配置"
|
||||
// @Success 200 {object} service.OAuthProvidersView
|
||||
// @Security BearerAuth
|
||||
// @Router /api/v1/settings/oauth [put]
|
||||
func (h *authxHandler) updateOAuthSettings(c *gin.Context, settings *service.SettingService) {
|
||||
var req service.UpdateOAuthInput
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user