From f0145544155914e2df47538f704cd6eab0ac5a10 Mon Sep 17 00:00:00 2001 From: Yang Luo Date: Sun, 14 Mar 2021 22:48:09 +0800 Subject: [PATCH] Generate real access token. --- controllers/token.go | 3 +- go.mod | 1 + go.sum | 2 + object/application.go | 7 ++-- object/token.go | 26 +++++++++++-- object/token_jwt.go | 69 ++++++++++++++++++++++++++++++++++ web/src/ApplicationEditPage.js | 16 ++++++-- web/src/ApplicationListPage.js | 1 + 8 files changed, 115 insertions(+), 10 deletions(-) create mode 100644 object/token_jwt.go diff --git a/controllers/token.go b/controllers/token.go index 8932767b..958c4cf9 100644 --- a/controllers/token.go +++ b/controllers/token.go @@ -70,13 +70,14 @@ func (c *ApiController) DeleteToken() { } func (c *ApiController) GetOAuthCode() { + userId := c.GetSessionUser() clientId := c.Input().Get("client_id") responseType := c.Input().Get("response_type") redirectUri := c.Input().Get("redirect_uri") scope := c.Input().Get("scope") state := c.Input().Get("state") - c.Data["json"] = object.GetOAuthCode(clientId, responseType, redirectUri, scope, state) + c.Data["json"] = object.GetOAuthCode(userId, clientId, responseType, redirectUri, scope, state) c.ServeJSON() } diff --git a/go.mod b/go.mod index 045a20bd..56109d14 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/astaxie/beego v1.12.3 github.com/casbin/casbin/v2 v2.23.4 github.com/casbin/xorm-adapter/v2 v2.2.0 + github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/go-sql-driver/mysql v1.5.0 github.com/google/uuid v1.2.0 github.com/qiangmzsx/string-adapter/v2 v2.1.0 diff --git a/go.sum b/go.sum index 05a2b3d1..b650c9b9 100644 --- a/go.sum +++ b/go.sum @@ -41,6 +41,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI= github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk= diff --git a/object/application.go b/object/application.go index 03831d48..27438d9d 100644 --- a/object/application.go +++ b/object/application.go @@ -33,9 +33,10 @@ type Application struct { Providers []string `xorm:"varchar(100)" json:"providers"` ProviderObjs []*Provider `xorm:"-" json:"providerObjs"` - ClientId string `xorm:"varchar(100)" json:"clientId"` - ClientSecret string `xorm:"varchar(100)" json:"clientSecret"` - RedirectUrls []string `xorm:"varchar(1000)" json:"redirectUrls"` + ClientId string `xorm:"varchar(100)" json:"clientId"` + ClientSecret string `xorm:"varchar(100)" json:"clientSecret"` + RedirectUrls []string `xorm:"varchar(1000)" json:"redirectUrls"` + ExpireInHours int `json:"expireInHours"` } func GetApplications(owner string) []*Application { diff --git a/object/token.go b/object/token.go index 6a6e539b..81fe5bee 100644 --- a/object/token.go +++ b/object/token.go @@ -123,7 +123,22 @@ func DeleteToken(token *Token) bool { return affected != 0 } -func GetOAuthCode(clientId string, responseType string, redirectUri string, scope string, state string) *Code { +func GetOAuthCode(userId string, clientId string, responseType string, redirectUri string, scope string, state string) *Code { + if userId == "" { + return &Code{ + Message: "please sign in first", + Code: "", + } + } + + user := GetUser(userId) + if user == nil { + return &Code{ + Message: "invalid user_id", + Code: "", + } + } + application := getApplicationByClientId(clientId) if application == nil { return &Code{ @@ -153,14 +168,19 @@ func GetOAuthCode(clientId string, responseType string, redirectUri string, scop } } + accessToken, err := generateJwtToken(application, user) + if err != nil { + panic(err) + } + token := &Token{ Owner: application.Owner, Name: util.GenerateId(), CreatedTime: util.GetCurrentTime(), Application: application.Name, Code: util.GenerateClientId(), - AccessToken: "", - ExpiresIn: 7200, + AccessToken: accessToken, + ExpiresIn: application.ExpireInHours * 60, Scope: scope, TokenType: "Bearer", } diff --git a/object/token_jwt.go b/object/token_jwt.go new file mode 100644 index 00000000..4a389c05 --- /dev/null +++ b/object/token_jwt.go @@ -0,0 +1,69 @@ +// Copyright 2021 The casbin Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package object + +import ( + "time" + + "github.com/dgrijalva/jwt-go" +) + +var jwtSecret = []byte("aaa") + +type Claims struct { + Username string `json:"username"` + Name string `json:"name"` + Email string `json:"email"` + jwt.StandardClaims +} + +func generateJwtToken(application *Application, user *User) (string, error) { + nowTime := time.Now() + expireTime := nowTime.Add(time.Duration(application.ExpireInHours) * time.Hour) + + claims := Claims{ + Username: user.Name, + Name: user.DisplayName, + Email: user.Email, + StandardClaims: jwt.StandardClaims{ + Audience: application.ClientId, + ExpiresAt: expireTime.Unix(), + Id: "", + IssuedAt: nowTime.Unix(), + Issuer: "casdoor", + NotBefore: nowTime.Unix(), + Subject: user.Id, + }, + } + + tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + token, err := tokenClaims.SignedString(jwtSecret) + + return token, err +} + +func parseJwtToken(token string) (*Claims, error) { + tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) { + return jwtSecret, nil + }) + + if tokenClaims != nil { + if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid { + return claims, nil + } + } + + return nil, err +} diff --git a/web/src/ApplicationEditPage.js b/web/src/ApplicationEditPage.js index d4f88695..0a34739e 100644 --- a/web/src/ApplicationEditPage.js +++ b/web/src/ApplicationEditPage.js @@ -71,9 +71,9 @@ class ApplicationEditPage extends React.Component { } parseApplicationField(key, value) { - // if ([].includes(key)) { - // value = Setting.myParseInt(value); - // } + if (["expireInHours"].includes(key)) { + value = Setting.myParseInt(value); + } return value; } @@ -206,6 +206,16 @@ class ApplicationEditPage extends React.Component { /> + + + {i18next.t("general:Expire In Hours")}: + + + { + this.updateApplicationField('expireInHours', e.target.value); + }} /> + + {i18next.t("application:Enable Password")}: diff --git a/web/src/ApplicationListPage.js b/web/src/ApplicationListPage.js index 3e1ba992..ea812862 100644 --- a/web/src/ApplicationListPage.js +++ b/web/src/ApplicationListPage.js @@ -52,6 +52,7 @@ class ApplicationListPage extends React.Component { EnablePassword: true, providers: [], redirectUrls: [], + expireInHours: 24 * 7, } }