feat: add "Face ID" login method (#2782)

Face Login via face-api.js
This commit is contained in:
HGZ-20
2024-03-16 09:04:00 +08:00
committed by GitHub
parent 57431a59ad
commit 391a533ce1
16 changed files with 506 additions and 7 deletions

View File

@ -757,6 +757,17 @@ func (application *Application) IsLdapEnabled() bool {
return false
}
func (application *Application) IsFaceIdEnabled() bool {
if len(application.SigninMethods) > 0 {
for _, signinMethod := range application.SigninMethods {
if signinMethod.Name == "Face ID" {
return true
}
}
}
return false
}
func IsOriginAllowed(origin string) (bool, error) {
applications, err := GetApplications("")
if err != nil {

View File

@ -190,6 +190,7 @@ type User struct {
MultiFactorAuths []*MfaProps `xorm:"-" json:"multiFactorAuths,omitempty"`
Invitation string `xorm:"varchar(100) index" json:"invitation"`
InvitationCode string `xorm:"varchar(100) index" json:"invitationCode"`
FaceIds []*FaceId `json:"faceIds"`
Ldap string `xorm:"ldap varchar(100)" json:"ldap"`
Properties map[string]string `json:"properties"`
@ -227,6 +228,11 @@ type ManagedAccount struct {
SigninUrl string `xorm:"varchar(200)" json:"signinUrl"`
}
type FaceId struct {
Name string `xorm:"varchar(100) notnull pk" json:"name"`
FaceIdData []float64 `json:"faceIdData"`
}
func GetUserFieldStringValue(user *User, fieldName string) (bool, string, error) {
val := reflect.ValueOf(*user)
fieldValue := val.FieldByName(fieldName)
@ -667,7 +673,7 @@ func UpdateUser(id string, user *User, columns []string, isAdmin bool) (bool, er
columns = []string{
"owner", "display_name", "avatar", "first_name", "last_name",
"location", "address", "country_code", "region", "language", "affiliation", "title", "id_card_type", "id_card", "homepage", "bio", "tag", "language", "gender", "birthday", "education", "score", "karma", "ranking", "signup_application",
"is_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts",
"is_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts", "face_ids",
"signin_wrong_times", "last_signin_wrong_time", "groups", "access_key", "access_secret",
"github", "google", "qq", "wechat", "facebook", "dingtalk", "weibo", "gitee", "linkedin", "wecom", "lark", "gitlab", "adfs",
"baidu", "alipay", "casdoor", "infoflow", "apple", "azuread", "azureadb2c", "slack", "steam", "bilibili", "okta", "douyin", "line", "amazon",

View File

@ -387,6 +387,11 @@ func CheckPermissionForUpdateUser(oldUser, newUser *User, isAdmin bool, lang str
itemsChanged = append(itemsChanged, item)
}
if newUser.FaceIds != nil {
item := GetAccountItemByName("Face ID", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.IsAdmin != newUser.IsAdmin {
item := GetAccountItemByName("Is admin", organization)
itemsChanged = append(itemsChanged, item)

View File

@ -17,6 +17,7 @@ package object
import (
"errors"
"fmt"
"math"
"math/rand"
"strings"
"time"
@ -236,6 +237,28 @@ func CheckSigninCode(user *User, dest, code, lang string) error {
}
}
func CheckFaceId(user *User, faceId []float64, lang string) error {
if len(user.FaceIds) == 0 {
return fmt.Errorf(i18n.Translate(lang, "check:Face data does not exist, cannot log in"))
}
for _, userFaceId := range user.FaceIds {
if faceId == nil || len(userFaceId.FaceIdData) != len(faceId) {
continue
}
var sumOfSquares float64
for i := 0; i < len(userFaceId.FaceIdData); i++ {
diff := userFaceId.FaceIdData[i] - faceId[i]
sumOfSquares += diff * diff
}
if math.Sqrt(sumOfSquares) < 0.25 {
return nil
}
}
return fmt.Errorf(i18n.Translate(lang, "check:Face data mismatch"))
}
func GetVerifyType(username string) (verificationCodeType string) {
if strings.Contains(username, "@") {
return VerifyTypeEmail