mirror of
				https://github.com/steveiliop56/tinyauth.git
				synced 2025-10-31 06:05:43 +00:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			6647c6cd78
			...
			l10n_main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 8aacadbb25 | 
| @@ -1,62 +1,62 @@ | |||||||
| { | { | ||||||
|     "loginTitle": "Welcome back, login with", |     "loginTitle": "Tervetuloa takaisin, kirjaudu sisään käyttäen", | ||||||
|     "loginTitleSimple": "Welcome back, please login", |     "loginTitleSimple": "Tervetuloa takaisin, ole hyvä ja kirjaudu", | ||||||
|     "loginDivider": "Or", |     "loginDivider": "Tai", | ||||||
|     "loginUsername": "Username", |     "loginUsername": "Käyttäjätunnus", | ||||||
|     "loginPassword": "Password", |     "loginPassword": "Salasana", | ||||||
|     "loginSubmit": "Login", |     "loginSubmit": "Kirjaudu", | ||||||
|     "loginFailTitle": "Failed to log in", |     "loginFailTitle": "Kirjautuminen epäonnistui", | ||||||
|     "loginFailSubtitle": "Please check your username and password", |     "loginFailSubtitle": "Tarkista käyttäjätunnuksesi ja salasanasi", | ||||||
|     "loginFailRateLimit": "You failed to login too many times. Please try again later", |     "loginFailRateLimit": "Kirjautuminen epäonnistui liian monta kertaa. Yritä myöhemmin uudelleen", | ||||||
|     "loginSuccessTitle": "Logged in", |     "loginSuccessTitle": "Olet kirjautunut sisään", | ||||||
|     "loginSuccessSubtitle": "Welcome back!", |     "loginSuccessSubtitle": "Tervetuloa takaisin!", | ||||||
|     "loginOauthFailTitle": "An error occurred", |     "loginOauthFailTitle": "Tapahtui virhe", | ||||||
|     "loginOauthFailSubtitle": "Failed to get OAuth URL", |     "loginOauthFailSubtitle": "OAuthin URL-osoitteen haku epäonnistui", | ||||||
|     "loginOauthSuccessTitle": "Redirecting", |     "loginOauthSuccessTitle": "Uudelleenohjataan", | ||||||
|     "loginOauthSuccessSubtitle": "Redirecting to your OAuth provider", |     "loginOauthSuccessSubtitle": "Uudelleenohjaus OAuth -palveluntarjoajallesi", | ||||||
|     "loginOauthAutoRedirectTitle": "OAuth Auto Redirect", |     "loginOauthAutoRedirectTitle": "Automaattinen OAuth -uudelleenohjaus", | ||||||
|     "loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.", |     "loginOauthAutoRedirectSubtitle": "Sinut ohjataan automaattisesti OAuth -palveluntarjoajallesi todentamista varten.", | ||||||
|     "loginOauthAutoRedirectButton": "Redirect now", |     "loginOauthAutoRedirectButton": "Siirry nyt", | ||||||
|     "continueTitle": "Continue", |     "continueTitle": "Jatka", | ||||||
|     "continueRedirectingTitle": "Redirecting...", |     "continueRedirectingTitle": "Uudelleenohjataan...", | ||||||
|     "continueRedirectingSubtitle": "You should be redirected to the app soon", |     "continueRedirectingSubtitle": "Sinun pitäisi ohjautua sovellukseen pian", | ||||||
|     "continueRedirectManually": "Redirect me manually", |     "continueRedirectManually": "Siirrä minut manuaalisesti", | ||||||
|     "continueInsecureRedirectTitle": "Insecure redirect", |     "continueInsecureRedirectTitle": "Turvaton uudelleenohjaus", | ||||||
|     "continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?", |     "continueInsecureRedirectSubtitle": "Yrität siirtyä suojatusta <code>https</code> -sivusta suojaamattomalle <code>http</code> -sivulle. Oletko varma, että haluat jatkaa?", | ||||||
|     "continueUntrustedRedirectTitle": "Untrusted redirect", |     "continueUntrustedRedirectTitle": "Ei-luotettu uudelleenohjaus", | ||||||
|     "continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?", |     "continueUntrustedRedirectSubtitle": "Yrität uudelleenohjata domainiin, joka ei vastaa määritettyä verkkotunnusta (<code>{{cookieDomain}}</code>). Oletko varma, että haluat jatkaa?", | ||||||
|     "logoutFailTitle": "Failed to log out", |     "logoutFailTitle": "Uloskirjautuminen epäonnistui", | ||||||
|     "logoutFailSubtitle": "Please try again", |     "logoutFailSubtitle": "Ole hyvä ja yritä uudelleen", | ||||||
|     "logoutSuccessTitle": "Logged out", |     "logoutSuccessTitle": "Kirjauduttu ulos", | ||||||
|     "logoutSuccessSubtitle": "You have been logged out", |     "logoutSuccessSubtitle": "Sinut on kirjattu ulos", | ||||||
|     "logoutTitle": "Logout", |     "logoutTitle": "Kirjaudu ulos", | ||||||
|     "logoutUsernameSubtitle": "You are currently logged in as <code>{{username}}</code>. Click the button below to logout.", |     "logoutUsernameSubtitle": "Olet kirjautuneena sisään tunnuksella <code>{{username}}</code>. Kirjaudu ulos alla olevasta painikkeesta.", | ||||||
|     "logoutOauthSubtitle": "You are currently logged in as <code>{{username}}</code> using the {{provider}} OAuth provider. Click the button below to logout.", |     "logoutOauthSubtitle": "Olet kirjautuneena sisään tunnuksella <code>{{username}}</code> OAuth palvelun {{provider}} kautta. Kirjaudu ulos alla olevasta painikkeesta.", | ||||||
|     "notFoundTitle": "Page not found", |     "notFoundTitle": "Sivua ei löydy", | ||||||
|     "notFoundSubtitle": "The page you are looking for does not exist.", |     "notFoundSubtitle": "Sivua, jota etsit ei ole olemassa.", | ||||||
|     "notFoundButton": "Go home", |     "notFoundButton": "Palaa kotinäkymään", | ||||||
|     "totpFailTitle": "Failed to verify code", |     "totpFailTitle": "Koodin vahvistus epäonnistui", | ||||||
|     "totpFailSubtitle": "Please check your code and try again", |     "totpFailSubtitle": "Tarkista koodisi ja yritä uudelleen", | ||||||
|     "totpSuccessTitle": "Verified", |     "totpSuccessTitle": "Vahvistettu", | ||||||
|     "totpSuccessSubtitle": "Redirecting to your app", |     "totpSuccessSubtitle": "Uudelleenohjataan sovelluksellesi", | ||||||
|     "totpTitle": "Enter your TOTP code", |     "totpTitle": "Syötä TOTP -koodisi", | ||||||
|     "totpSubtitle": "Please enter the code from your authenticator app.", |     "totpSubtitle": "Ole hyvä ja syötä koodi todennussovelluksestasi.", | ||||||
|     "unauthorizedTitle": "Unauthorized", |     "unauthorizedTitle": "Ei sallittu", | ||||||
|     "unauthorizedResourceSubtitle": "The user with username <code>{{username}}</code> is not authorized to access the resource <code>{{resource}}</code>.", |     "unauthorizedResourceSubtitle": "Käyttäjällä <code>{{username}}</code> ei ole pääsyä kohteeseen <code>{{resource}}</code>.", | ||||||
|     "unauthorizedLoginSubtitle": "The user with username <code>{{username}}</code> is not authorized to login.", |     "unauthorizedLoginSubtitle": "Käyttäjällä <code>{{username}}</code> ei ole lupaa kirjautua.", | ||||||
|     "unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.", |     "unauthorizedGroupsSubtitle": "Käyttäjä <code>{{username}}</code> ei ole ryhmässä, joka vaaditaan pääsyyn kohteeseen <code>{{resource}}</code>.", | ||||||
|     "unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.", |     "unauthorizedIpSubtitle": "IP osoitteestasi <code>{{ip}}</code> ei ole pääsyä kohteeseen <code>{{resource}}</code>.", | ||||||
|     "unauthorizedButton": "Try again", |     "unauthorizedButton": "Yritä uudelleen", | ||||||
|     "cancelTitle": "Cancel", |     "cancelTitle": "Peruuta", | ||||||
|     "forgotPasswordTitle": "Forgot your password?", |     "forgotPasswordTitle": "Unohditko salasanasi?", | ||||||
|     "failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.", |     "failedToFetchProvidersTitle": "Todennuspalvelujen tarjoajien lataaminen epäonnistui. Tarkista määrityksesi.", | ||||||
|     "errorTitle": "An error occurred", |     "errorTitle": "Tapahtui virhe", | ||||||
|     "errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.", |     "errorSubtitle": "Tapahtui virhe yritettäessä suorittaa tämä toiminto. Ole hyvä ja tarkista konsoli saadaksesi lisätietoja.", | ||||||
|     "forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.", |     "forgotPasswordMessage": "Voit nollata salasanasi vaihtamalla ympäristömuuttujan `USERS`.", | ||||||
|     "fieldRequired": "This field is required", |     "fieldRequired": "Tämä kenttä on pakollinen", | ||||||
|     "invalidInput": "Invalid input", |     "invalidInput": "Virheellinen syöte", | ||||||
|     "domainWarningTitle": "Invalid Domain", |     "domainWarningTitle": "Virheellinen verkkotunnus", | ||||||
|     "domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.", |     "domainWarningSubtitle": "Tämä instanssi on määritelty käyttämään osoitetta <code>{{appUrl}}</code>, mutta nykyinen osoite on <code>{{currentUrl}}</code>. Jos jatkat, saatat törmätä ongelmiin autentikoinnissa.", | ||||||
|     "ignoreTitle": "Ignore", |     "ignoreTitle": "Jätä huomiotta", | ||||||
|     "goToCorrectDomainTitle": "Go to correct domain" |     "goToCorrectDomainTitle": "Siirry oikeaan verkkotunnukseen" | ||||||
| } | } | ||||||
| @@ -2,7 +2,6 @@ package bootstrap | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"bytes" | 	"bytes" | ||||||
| 	"context" |  | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| @@ -14,13 +13,11 @@ import ( | |||||||
| 	"tinyauth/internal/config" | 	"tinyauth/internal/config" | ||||||
| 	"tinyauth/internal/controller" | 	"tinyauth/internal/controller" | ||||||
| 	"tinyauth/internal/middleware" | 	"tinyauth/internal/middleware" | ||||||
| 	"tinyauth/internal/model" |  | ||||||
| 	"tinyauth/internal/service" | 	"tinyauth/internal/service" | ||||||
| 	"tinyauth/internal/utils" | 	"tinyauth/internal/utils" | ||||||
|  |  | ||||||
| 	"github.com/gin-gonic/gin" | 	"github.com/gin-gonic/gin" | ||||||
| 	"github.com/rs/zerolog/log" | 	"github.com/rs/zerolog/log" | ||||||
| 	"gorm.io/gorm" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Controller interface { | type Controller interface { | ||||||
| @@ -280,10 +277,6 @@ func (app *BootstrapApp) Setup() error { | |||||||
| 		go app.heartbeat() | 		go app.heartbeat() | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Start DB cleanup routine |  | ||||||
| 	log.Debug().Msg("Starting database cleanup routine") |  | ||||||
| 	go app.dbCleanup(database) |  | ||||||
|  |  | ||||||
| 	// Start server | 	// Start server | ||||||
| 	address := fmt.Sprintf("%s:%d", app.config.Address, app.config.Port) | 	address := fmt.Sprintf("%s:%d", app.config.Address, app.config.Port) | ||||||
| 	log.Info().Msgf("Starting server on %s", address) | 	log.Info().Msgf("Starting server on %s", address) | ||||||
| @@ -345,17 +338,3 @@ func (app *BootstrapApp) heartbeat() { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (app *BootstrapApp) dbCleanup(db *gorm.DB) { |  | ||||||
| 	ticker := time.NewTicker(time.Duration(30) * time.Minute) |  | ||||||
| 	defer ticker.Stop() |  | ||||||
| 	ctx := context.Background() |  | ||||||
|  |  | ||||||
| 	for ; true; <-ticker.C { |  | ||||||
| 		log.Debug().Msg("Cleaning up old database sessions") |  | ||||||
| 		_, err := gorm.G[model.Session](db).Where("expiry < ?", time.Now().UnixMilli()).Delete(ctx) |  | ||||||
| 		if err != nil { |  | ||||||
| 			log.Error().Err(err).Msg("Failed to cleanup old sessions") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -72,7 +72,6 @@ func (controller *OAuthController) oauthURLHandler(c *gin.Context) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	service.GenerateVerifier() |  | ||||||
| 	state := service.GenerateState() | 	state := service.GenerateState() | ||||||
| 	authURL := service.GetAuthURL(state) | 	authURL := service.GetAuthURL(state) | ||||||
| 	c.SetCookie(controller.config.CSRFCookieName, state, int(time.Hour.Seconds()), "/", fmt.Sprintf(".%s", controller.config.CookieDomain), controller.config.SecureCookie, true) | 	c.SetCookie(controller.config.CSRFCookieName, state, int(time.Hour.Seconds()), "/", fmt.Sprintf(".%s", controller.config.CookieDomain), controller.config.SecureCookie, true) | ||||||
|   | |||||||
| @@ -1,8 +1,6 @@ | |||||||
| package service | package service | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" |  | ||||||
| 	"errors" |  | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"regexp" | 	"regexp" | ||||||
| 	"strings" | 	"strings" | ||||||
| @@ -43,7 +41,6 @@ type AuthService struct { | |||||||
| 	loginMutex    sync.RWMutex | 	loginMutex    sync.RWMutex | ||||||
| 	ldap          *LdapService | 	ldap          *LdapService | ||||||
| 	database      *gorm.DB | 	database      *gorm.DB | ||||||
| 	ctx           context.Context |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewAuthService(config AuthServiceConfig, docker *DockerService, ldap *LdapService, database *gorm.DB) *AuthService { | func NewAuthService(config AuthServiceConfig, docker *DockerService, ldap *LdapService, database *gorm.DB) *AuthService { | ||||||
| @@ -57,7 +54,6 @@ func NewAuthService(config AuthServiceConfig, docker *DockerService, ldap *LdapS | |||||||
| } | } | ||||||
|  |  | ||||||
| func (auth *AuthService) Init() error { | func (auth *AuthService) Init() error { | ||||||
| 	auth.ctx = context.Background() |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -217,7 +213,7 @@ func (auth *AuthService) CreateSessionCookie(c *gin.Context, data *config.Sessio | |||||||
| 		OAuthName:   data.OAuthName, | 		OAuthName:   data.OAuthName, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	err = gorm.G[model.Session](auth.database).Create(auth.ctx, &session) | 	err = auth.database.Create(&session).Error | ||||||
|  |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| @@ -235,10 +231,10 @@ func (auth *AuthService) DeleteSessionCookie(c *gin.Context) error { | |||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	_, err = gorm.G[model.Session](auth.database).Where("uuid = ?", cookie).Delete(auth.ctx) | 	res := auth.database.Unscoped().Where("uuid = ?", cookie).Delete(&model.Session{}) | ||||||
|  |  | ||||||
| 	if err != nil { | 	if res.Error != nil { | ||||||
| 		return err | 		return res.Error | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	c.SetCookie(auth.config.SessionCookieName, "", -1, "/", fmt.Sprintf(".%s", auth.config.CookieDomain), auth.config.SecureCookie, true) | 	c.SetCookie(auth.config.SessionCookieName, "", -1, "/", fmt.Sprintf(".%s", auth.config.CookieDomain), auth.config.SecureCookie, true) | ||||||
| @@ -253,13 +249,15 @@ func (auth *AuthService) GetSessionCookie(c *gin.Context) (config.SessionCookie, | |||||||
| 		return config.SessionCookie{}, err | 		return config.SessionCookie{}, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	session, err := gorm.G[model.Session](auth.database).Where("uuid = ?", cookie).First(auth.ctx) | 	var session model.Session | ||||||
|  |  | ||||||
| 	if err != nil { | 	res := auth.database.Unscoped().Where("uuid = ?", cookie).First(&session) | ||||||
| 		return config.SessionCookie{}, err |  | ||||||
|  | 	if res.Error != nil { | ||||||
|  | 		return config.SessionCookie{}, res.Error | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if errors.Is(err, gorm.ErrRecordNotFound) { | 	if res.RowsAffected == 0 { | ||||||
| 		return config.SessionCookie{}, fmt.Errorf("session not found") | 		return config.SessionCookie{}, fmt.Errorf("session not found") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -59,8 +59,10 @@ func (generic *GenericOAuthService) Init() error { | |||||||
| 	ctx := context.Background() | 	ctx := context.Background() | ||||||
|  |  | ||||||
| 	ctx = context.WithValue(ctx, oauth2.HTTPClient, httpClient) | 	ctx = context.WithValue(ctx, oauth2.HTTPClient, httpClient) | ||||||
|  | 	verifier := oauth2.GenerateVerifier() | ||||||
|  |  | ||||||
| 	generic.context = ctx | 	generic.context = ctx | ||||||
|  | 	generic.verifier = verifier | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -74,12 +76,6 @@ func (generic *GenericOAuthService) GenerateState() string { | |||||||
| 	return state | 	return state | ||||||
| } | } | ||||||
|  |  | ||||||
| func (generic *GenericOAuthService) GenerateVerifier() string { |  | ||||||
| 	verifier := oauth2.GenerateVerifier() |  | ||||||
| 	generic.verifier = verifier |  | ||||||
| 	return verifier |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (generic *GenericOAuthService) GetAuthURL(state string) string { | func (generic *GenericOAuthService) GetAuthURL(state string) string { | ||||||
| 	return generic.config.AuthCodeURL(state, oauth2.AccessTypeOffline, oauth2.S256ChallengeOption(generic.verifier)) | 	return generic.config.AuthCodeURL(state, oauth2.AccessTypeOffline, oauth2.S256ChallengeOption(generic.verifier)) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -53,7 +53,10 @@ func (github *GithubOAuthService) Init() error { | |||||||
| 	httpClient := &http.Client{} | 	httpClient := &http.Client{} | ||||||
| 	ctx := context.Background() | 	ctx := context.Background() | ||||||
| 	ctx = context.WithValue(ctx, oauth2.HTTPClient, httpClient) | 	ctx = context.WithValue(ctx, oauth2.HTTPClient, httpClient) | ||||||
|  | 	verifier := oauth2.GenerateVerifier() | ||||||
|  |  | ||||||
| 	github.context = ctx | 	github.context = ctx | ||||||
|  | 	github.verifier = verifier | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -67,12 +70,6 @@ func (github *GithubOAuthService) GenerateState() string { | |||||||
| 	return state | 	return state | ||||||
| } | } | ||||||
|  |  | ||||||
| func (github *GithubOAuthService) GenerateVerifier() string { |  | ||||||
| 	verifier := oauth2.GenerateVerifier() |  | ||||||
| 	github.verifier = verifier |  | ||||||
| 	return verifier |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (github *GithubOAuthService) GetAuthURL(state string) string { | func (github *GithubOAuthService) GetAuthURL(state string) string { | ||||||
| 	return github.config.AuthCodeURL(state, oauth2.AccessTypeOffline, oauth2.S256ChallengeOption(github.verifier)) | 	return github.config.AuthCodeURL(state, oauth2.AccessTypeOffline, oauth2.S256ChallengeOption(github.verifier)) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -48,7 +48,10 @@ func (google *GoogleOAuthService) Init() error { | |||||||
| 	httpClient := &http.Client{} | 	httpClient := &http.Client{} | ||||||
| 	ctx := context.Background() | 	ctx := context.Background() | ||||||
| 	ctx = context.WithValue(ctx, oauth2.HTTPClient, httpClient) | 	ctx = context.WithValue(ctx, oauth2.HTTPClient, httpClient) | ||||||
|  | 	verifier := oauth2.GenerateVerifier() | ||||||
|  |  | ||||||
| 	google.context = ctx | 	google.context = ctx | ||||||
|  | 	google.verifier = verifier | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -62,12 +65,6 @@ func (oauth *GoogleOAuthService) GenerateState() string { | |||||||
| 	return state | 	return state | ||||||
| } | } | ||||||
|  |  | ||||||
| func (google *GoogleOAuthService) GenerateVerifier() string { |  | ||||||
| 	verifier := oauth2.GenerateVerifier() |  | ||||||
| 	google.verifier = verifier |  | ||||||
| 	return verifier |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (google *GoogleOAuthService) GetAuthURL(state string) string { | func (google *GoogleOAuthService) GetAuthURL(state string) string { | ||||||
| 	return google.config.AuthCodeURL(state, oauth2.AccessTypeOffline, oauth2.S256ChallengeOption(google.verifier)) | 	return google.config.AuthCodeURL(state, oauth2.AccessTypeOffline, oauth2.S256ChallengeOption(google.verifier)) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -11,7 +11,6 @@ import ( | |||||||
| type OAuthService interface { | type OAuthService interface { | ||||||
| 	Init() error | 	Init() error | ||||||
| 	GenerateState() string | 	GenerateState() string | ||||||
| 	GenerateVerifier() string |  | ||||||
| 	GetAuthURL(state string) string | 	GetAuthURL(state string) string | ||||||
| 	VerifyCode(code string) error | 	VerifyCode(code string) error | ||||||
| 	Userinfo() (config.Claims, error) | 	Userinfo() (config.Claims, error) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user