alist/server/middlewares/auth.go
千石 280960ce3e
Some checks are pending
auto_lang / auto generate lang.json (1.21, ubuntu-latest) (push) Waiting to run
beta release / Beta Release Changelog (1.21, ubuntu-latest) (push) Waiting to run
beta release / Beta Release (md5, !(*musl*|*windows-arm64*|*android*|*freebsd*)) (push) Blocked by required conditions
beta release / Beta Release (md5-android, android-*) (push) Blocked by required conditions
beta release / Beta Release (md5-freebsd, freebsd-*) (push) Blocked by required conditions
beta release / Beta Release (md5-linux-musl, linux-!(arm*)-musl*) (push) Blocked by required conditions
beta release / Beta Release (md5-linux-musl-arm, linux-arm*-musl*) (push) Blocked by required conditions
beta release / Beta Release (md5-windows-arm64, windows-arm64) (push) Blocked by required conditions
beta release / Beta Release Desktop (push) Blocked by required conditions
build / Build (ubuntu-latest, android-arm64) (push) Waiting to run
build / Build (ubuntu-latest, darwin-amd64) (push) Waiting to run
build / Build (ubuntu-latest, darwin-arm64) (push) Waiting to run
build / Build (ubuntu-latest, linux-amd64-musl) (push) Waiting to run
build / Build (ubuntu-latest, linux-arm64-musl) (push) Waiting to run
build / Build (ubuntu-latest, windows-amd64) (push) Waiting to run
build / Build (ubuntu-latest, windows-arm64) (push) Waiting to run
release_docker / Build Binaries for Docker Release (push) Waiting to run
release_docker / Release Docker image (, latest, ) (push) Blocked by required conditions
release_docker / Release Docker image (INSTALL_ARIA2=true, aria2, suffix=-aria2,onlatest=true) (push) Blocked by required conditions
release_docker / Release Docker image (INSTALL_FFMPEG=true INSTALL_ARIA2=true , aio, suffix=-aio,onlatest=true) (push) Blocked by required conditions
release_docker / Release Docker image (INSTALL_FFMPEG=true, ffmpeg, suffix=-ffmpeg,onlatest=true) (push) Blocked by required conditions
feat(user-db): enhance user management with role-based queries (allow-edit-role-guest) (#9234)
- Add `GetUsersByRole` function to fetch users based on their roles.
- Extend `UpdateUserBasePathPrefix` to accept optional user lists.
- Ensure path cleaning in `UpdateUserBasePathPrefix` for consistency.
- Integrate guest role fetching in `auth.go` middleware.
- Utilize `GetUsersByRole` in `role.go` for base path modifications.
- Remove redundant line in `role.go` role modification logic.
2025-07-30 13:15:35 +08:00

181 lines
4.0 KiB
Go

package middlewares
import (
"crypto/subtle"
"fmt"
"github.com/alist-org/alist/v3/internal/conf"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/internal/op"
"github.com/alist-org/alist/v3/internal/setting"
"github.com/alist-org/alist/v3/server/common"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
)
// Auth is a middleware that checks if the user is logged in.
// if token is empty, set user to guest
func Auth(c *gin.Context) {
token := c.GetHeader("Authorization")
if subtle.ConstantTimeCompare([]byte(token), []byte(setting.GetStr(conf.Token))) == 1 {
admin, err := op.GetAdmin()
if err != nil {
common.ErrorResp(c, err, 500)
c.Abort()
return
}
c.Set("user", admin)
log.Debugf("use admin token: %+v", admin)
c.Next()
return
}
if token == "" {
guest, err := op.GetGuest()
if err != nil {
common.ErrorResp(c, err, 500)
c.Abort()
return
}
if guest.Disabled {
common.ErrorStrResp(c, "Guest user is disabled, login please", 401)
c.Abort()
return
}
if len(guest.Role) > 0 {
roles, err := op.GetRolesByUserID(guest.ID)
if err != nil {
common.ErrorStrResp(c, fmt.Sprintf("Fail to load guest roles: %v", err), 500)
c.Abort()
return
}
guest.RolesDetail = roles
}
c.Set("user", guest)
log.Debugf("use empty token: %+v", guest)
c.Next()
return
}
userClaims, err := common.ParseToken(token)
if err != nil {
common.ErrorResp(c, err, 401)
c.Abort()
return
}
user, err := op.GetUserByName(userClaims.Username)
if err != nil {
common.ErrorResp(c, err, 401)
c.Abort()
return
}
// validate password timestamp
if userClaims.PwdTS != user.PwdTS {
common.ErrorStrResp(c, "Password has been changed, login please", 401)
c.Abort()
return
}
if user.Disabled {
common.ErrorStrResp(c, "Current user is disabled, replace please", 401)
c.Abort()
return
}
if len(user.Role) > 0 {
roles, err := op.GetRolesByUserID(user.ID)
if err != nil {
common.ErrorStrResp(c, fmt.Sprintf("Fail to load roles: %v", err), 500)
c.Abort()
return
}
user.RolesDetail = roles
}
c.Set("user", user)
log.Debugf("use login token: %+v", user)
c.Next()
}
func Authn(c *gin.Context) {
token := c.GetHeader("Authorization")
if subtle.ConstantTimeCompare([]byte(token), []byte(setting.GetStr(conf.Token))) == 1 {
admin, err := op.GetAdmin()
if err != nil {
common.ErrorResp(c, err, 500)
c.Abort()
return
}
c.Set("user", admin)
log.Debugf("use admin token: %+v", admin)
c.Next()
return
}
if token == "" {
guest, err := op.GetGuest()
if err != nil {
common.ErrorResp(c, err, 500)
c.Abort()
return
}
c.Set("user", guest)
log.Debugf("use empty token: %+v", guest)
c.Next()
return
}
userClaims, err := common.ParseToken(token)
if err != nil {
common.ErrorResp(c, err, 401)
c.Abort()
return
}
user, err := op.GetUserByName(userClaims.Username)
if err != nil {
common.ErrorResp(c, err, 401)
c.Abort()
return
}
// validate password timestamp
if userClaims.PwdTS != user.PwdTS {
common.ErrorStrResp(c, "Password has been changed, login please", 401)
c.Abort()
return
}
if user.Disabled {
common.ErrorStrResp(c, "Current user is disabled, replace please", 401)
c.Abort()
return
}
if len(user.Role) > 0 {
var roles []model.Role
for _, roleID := range user.Role {
role, err := op.GetRole(uint(roleID))
if err != nil {
common.ErrorStrResp(c, fmt.Sprintf("load role %d failed", roleID), 500)
c.Abort()
return
}
roles = append(roles, *role)
}
user.RolesDetail = roles
}
c.Set("user", user)
log.Debugf("use login token: %+v", user)
c.Next()
}
func AuthNotGuest(c *gin.Context) {
user := c.MustGet("user").(*model.User)
if user.IsGuest() {
common.ErrorStrResp(c, "You are a guest", 403)
c.Abort()
} else {
c.Next()
}
}
func AuthAdmin(c *gin.Context) {
user := c.MustGet("user").(*model.User)
if !user.IsAdmin() {
common.ErrorStrResp(c, "You are not an admin", 403)
c.Abort()
} else {
c.Next()
}
}