From 2a0dcd746f915e6f34a476d05aed0f820e08d21b Mon Sep 17 00:00:00 2001 From: Steve0x2a Date: Wed, 2 Mar 2022 20:37:31 +0800 Subject: [PATCH] feat: add token logout endpoint (#526) Signed-off-by: Steve0x2a --- authz/authz.go | 1 + controllers/token.go | 24 ++++ object/application.go | 13 ++ object/token.go | 19 +++ routers/router.go | 1 + swagger/swagger.json | 267 +++++++++++++++++++++++++++++++++++++++++- swagger/swagger.yml | 181 +++++++++++++++++++++++++++- 7 files changed, 494 insertions(+), 12 deletions(-) diff --git a/authz/authz.go b/authz/authz.go index f999d150..dc66f31e 100644 --- a/authz/authz.go +++ b/authz/authz.go @@ -83,6 +83,7 @@ p, *, *, GET, /api/get-account, *, * p, *, *, GET, /api/userinfo, *, * p, *, *, POST, /api/login/oauth/access_token, *, * p, *, *, POST, /api/login/oauth/refresh_token, *, * +p, *, *, GET, /api/login/oauth/logout, *, * p, *, *, GET, /api/get-application, *, * p, *, *, GET, /api/get-users, *, * p, *, *, GET, /api/get-user, *, * diff --git a/controllers/token.go b/controllers/token.go index 5f13db13..3e681474 100644 --- a/controllers/token.go +++ b/controllers/token.go @@ -16,6 +16,7 @@ package controllers import ( "encoding/json" + "net/http" "github.com/astaxie/beego/utils/pagination" "github.com/casdoor/casdoor/object" @@ -186,6 +187,7 @@ func (c *ApiController) GetOAuthToken() { // RefreshToken // @Title RefreshToken +// @Tag Token API // @Description refresh OAuth access token // @Param grant_type query string true "OAuth grant type" // @Param refresh_token query string true "OAuth refresh token" @@ -205,3 +207,25 @@ func (c *ApiController) RefreshToken() { c.Data["json"] = object.RefreshToken(grantType, refreshToken, scope, clientId, clientSecret, host) c.ServeJSON() } + +// TokenLogout +// @Title TokenLogout +// @Tag Token API +// @Description delete token by AccessToken +// @Param id_token_hint query string true "id_token_hint" +// @Param post_logout_redirect_uri query string false "post_logout_redirect_uri" +// @Param state query string true "state" +// @Success 200 {object} controllers.Response The Response object +// @router /login/oauth/logout [get] +func (c *ApiController) TokenLogout() { + token := c.Input().Get("id_token_hint") + flag, application := object.DeleteTokenByAceessToken(token) + redirectUri := c.Input().Get("post_logout_redirect_uri") + state := c.Input().Get("state") + if application != nil && object.CheckRedirectUriValid(application, redirectUri) { + c.Ctx.Redirect(http.StatusFound, redirectUri+"?state="+state) + return + } + c.Data["json"] = wrapActionResponse(flag) + c.ServeJSON() +} diff --git a/object/application.go b/object/application.go index 61e4548a..45eeec25 100644 --- a/object/application.go +++ b/object/application.go @@ -16,6 +16,7 @@ package object import ( "fmt" + "strings" "github.com/casdoor/casdoor/util" "xorm.io/core" @@ -283,3 +284,15 @@ func DeleteApplication(application *Application) bool { func (application *Application) GetId() string { return fmt.Sprintf("%s/%s", application.Owner, application.Name) } + +func CheckRedirectUriValid(application *Application, redirectUri string) bool { + var validUri = false + for _, tmpUri := range application.RedirectUris { + fmt.Println(tmpUri, redirectUri) + if strings.Contains(redirectUri, tmpUri) { + validUri = true + break + } + } + return validUri +} diff --git a/object/token.go b/object/token.go index 56a1d930..0c888a1e 100644 --- a/object/token.go +++ b/object/token.go @@ -169,6 +169,25 @@ func DeleteToken(token *Token) bool { return affected != 0 } +func DeleteTokenByAceessToken(accessToken string) (bool, *Application) { + token := Token{AccessToken: accessToken} + existed, err := adapter.Engine.Get(&token) + if err != nil { + panic(err) + } + + if !existed { + return false, nil + } + application := getApplication(token.Owner, token.Application) + affected, err := adapter.Engine.Where("access_token=?", accessToken).Delete(&Token{}) + if err != nil { + panic(err) + } + + return affected != 0, application +} + func GetTokenByAccessToken(accessToken string) *Token { //Check if the accessToken is in the database token := Token{AccessToken: accessToken} diff --git a/routers/router.go b/routers/router.go index 1a7c4b0e..e6b65225 100644 --- a/routers/router.go +++ b/routers/router.go @@ -127,6 +127,7 @@ func initAPI() { beego.Router("/api/login/oauth/code", &controllers.ApiController{}, "POST:GetOAuthCode") beego.Router("/api/login/oauth/access_token", &controllers.ApiController{}, "POST:GetOAuthToken") beego.Router("/api/login/oauth/refresh_token", &controllers.ApiController{}, "POST:RefreshToken") + beego.Router("/api/login/oauth/logout", &controllers.ApiController{}, "GET:TokenLogout") beego.Router("/api/get-records", &controllers.ApiController{}, "GET:GetRecords") beego.Router("/api/get-records-filter", &controllers.ApiController{}, "POST:GetRecordsByFilter") diff --git a/swagger/swagger.json b/swagger/swagger.json index ccd30f04..469fd907 100644 --- a/swagger/swagger.json +++ b/swagger/swagger.json @@ -174,6 +174,34 @@ } } }, + "/api/add-product": { + "post": { + "tags": [ + "Product API" + ], + "description": "add product", + "operationId": "ApiController.AddProduct", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "The details of the product", + "required": true, + "schema": { + "$ref": "#/definitions/object.Product" + } + } + ], + "responses": { + "200": { + "description": "The Response object", + "schema": { + "$ref": "#/definitions/controllers.Response" + } + } + } + } + }, "/api/add-provider": { "post": { "tags": [ @@ -614,6 +642,34 @@ } } }, + "/api/delete-product": { + "post": { + "tags": [ + "Product API" + ], + "description": "delete product", + "operationId": "ApiController.DeleteProduct", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "The details of the product", + "required": true, + "schema": { + "$ref": "#/definitions/object.Product" + } + } + ], + "responses": { + "200": { + "description": "The Response object", + "schema": { + "$ref": "#/definitions/controllers.Response" + } + } + } + } + }, "/api/delete-provider": { "post": { "tags": [ @@ -1159,6 +1215,61 @@ } } }, + "/api/get-product": { + "get": { + "tags": [ + "Product API" + ], + "description": "get product", + "operationId": "ApiController.GetProduct", + "parameters": [ + { + "in": "query", + "name": "id", + "description": "The id of the product", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "The Response object", + "schema": { + "$ref": "#/definitions/object.Product" + } + } + } + } + }, + "/api/get-products": { + "get": { + "tags": [ + "Product API" + ], + "description": "get products", + "operationId": "ApiController.GetProducts", + "parameters": [ + { + "in": "query", + "name": "owner", + "description": "The owner of products", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "The Response object", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/object.Product" + } + } + } + } + } + }, "/api/get-provider": { "get": { "tags": [ @@ -1825,8 +1936,50 @@ } } }, + "/api/login/oauth/logout": { + "get": { + "tags": [ + "Token API" + ], + "description": "delete token by AccessToken", + "operationId": "ApiController.TokenLogout", + "parameters": [ + { + "in": "query", + "name": "id_token_hint", + "description": "id_token_hint", + "required": true, + "type": "string" + }, + { + "in": "query", + "name": "post_logout_redirect_uri", + "description": "post_logout_redirect_uri", + "type": "string" + }, + { + "in": "query", + "name": "state", + "description": "state", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "The Response object", + "schema": { + "$ref": "#/definitions/controllers.Response" + } + } + } + } + }, "/api/login/oauth/refresh_token": { "post": { + "tags": [ + "Token API" + ], "description": "refresh OAuth access token", "operationId": "ApiController.RefreshToken", "parameters": [ @@ -2231,6 +2384,41 @@ } } }, + "/api/update-product": { + "post": { + "tags": [ + "Product API" + ], + "description": "update product", + "operationId": "ApiController.UpdateProduct", + "parameters": [ + { + "in": "query", + "name": "id", + "description": "The id of the product", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "description": "The details of the product", + "required": true, + "schema": { + "$ref": "#/definitions/object.Product" + } + } + ], + "responses": { + "200": { + "description": "The Response object", + "schema": { + "$ref": "#/definitions/controllers.Response" + } + } + } + } + }, "/api/update-provider": { "post": { "tags": [ @@ -2476,11 +2664,11 @@ } }, "definitions": { - "1867.0xc00029b560.false": { + "2015.0xc0000edb90.false": { "title": "false", "type": "object" }, - "1901.0xc00029b590.false": { + "2049.0xc0000edbc0.false": { "title": "false", "type": "object" }, @@ -2497,10 +2685,10 @@ "type": "object", "properties": { "data": { - "$ref": "#/definitions/1867.0xc00029b560.false" + "$ref": "#/definitions/2015.0xc0000edb90.false" }, "data2": { - "$ref": "#/definitions/1901.0xc00029b590.false" + "$ref": "#/definitions/2049.0xc0000edbc0.false" }, "msg": { "type": "string" @@ -2521,10 +2709,10 @@ "type": "object", "properties": { "data": { - "$ref": "#/definitions/1867.0xc00029b560.false" + "$ref": "#/definitions/2015.0xc0000edb90.false" }, "data2": { - "$ref": "#/definitions/1901.0xc00029b590.false" + "$ref": "#/definitions/2049.0xc0000edbc0.false" }, "msg": { "type": "string" @@ -2606,6 +2794,12 @@ "forgetUrl": { "type": "string" }, + "grantTypes": { + "type": "array", + "items": { + "type": "string" + } + }, "homepageUrl": { "type": "string" }, @@ -2854,6 +3048,57 @@ } } }, + "object.Product": { + "title": "Product", + "type": "object", + "properties": { + "createdTime": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "detail": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "image": { + "type": "string" + }, + "name": { + "type": "string" + }, + "owner": { + "type": "string" + }, + "price": { + "type": "integer", + "format": "int64" + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + }, + "quantity": { + "type": "integer", + "format": "int64" + }, + "sold": { + "type": "integer", + "format": "int64" + }, + "state": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, "object.Provider": { "title": "Provider", "type": "object", @@ -3258,6 +3503,9 @@ "facebook": { "type": "string" }, + "firstName": { + "type": "string" + }, "gender": { "type": "string" }, @@ -3309,12 +3557,19 @@ "isOnline": { "type": "boolean" }, + "karma": { + "type": "integer", + "format": "int64" + }, "language": { "type": "string" }, "lark": { "type": "string" }, + "lastName": { + "type": "string" + }, "lastSigninIp": { "type": "string" }, diff --git a/swagger/swagger.yml b/swagger/swagger.yml index 74330bc6..26e4da6b 100644 --- a/swagger/swagger.yml +++ b/swagger/swagger.yml @@ -112,6 +112,24 @@ paths: description: The Response object schema: $ref: '#/definitions/controllers.Response' + /api/add-product: + post: + tags: + - Product API + description: add product + operationId: ApiController.AddProduct + parameters: + - in: body + name: body + description: The details of the product + required: true + schema: + $ref: '#/definitions/object.Product' + responses: + "200": + description: The Response object + schema: + $ref: '#/definitions/controllers.Response' /api/add-provider: post: tags: @@ -396,6 +414,24 @@ paths: description: The Response object schema: $ref: '#/definitions/controllers.Response' + /api/delete-product: + post: + tags: + - Product API + description: delete product + operationId: ApiController.DeleteProduct + parameters: + - in: body + name: body + description: The details of the product + required: true + schema: + $ref: '#/definitions/object.Product' + responses: + "200": + description: The Response object + schema: + $ref: '#/definitions/controllers.Response' /api/delete-provider: post: tags: @@ -750,6 +786,42 @@ paths: type: array items: $ref: '#/definitions/object.Permission' + /api/get-product: + get: + tags: + - Product API + description: get product + operationId: ApiController.GetProduct + parameters: + - in: query + name: id + description: The id of the product + required: true + type: string + responses: + "200": + description: The Response object + schema: + $ref: '#/definitions/object.Product' + /api/get-products: + get: + tags: + - Product API + description: get products + operationId: ApiController.GetProducts + parameters: + - in: query + name: owner + description: The owner of products + required: true + type: string + responses: + "200": + description: The Response object + schema: + type: array + items: + $ref: '#/definitions/object.Product' /api/get-provider: get: tags: @@ -1190,8 +1262,36 @@ paths: description: The Response object schema: $ref: '#/definitions/object.TokenWrapper' + /api/login/oauth/logout: + get: + tags: + - Token API + description: delete token by AccessToken + operationId: ApiController.TokenLogout + parameters: + - in: query + name: id_token_hint + description: id_token_hint + required: true + type: string + - in: query + name: post_logout_redirect_uri + description: post_logout_redirect_uri + type: string + - in: query + name: state + description: state + required: true + type: string + responses: + "200": + description: The Response object + schema: + $ref: '#/definitions/controllers.Response' /api/login/oauth/refresh_token: post: + tags: + - Token API description: refresh OAuth access token operationId: ApiController.RefreshToken parameters: @@ -1460,6 +1560,29 @@ paths: description: The Response object schema: $ref: '#/definitions/controllers.Response' + /api/update-product: + post: + tags: + - Product API + description: update product + operationId: ApiController.UpdateProduct + parameters: + - in: query + name: id + description: The id of the product + required: true + type: string + - in: body + name: body + description: The details of the product + required: true + schema: + $ref: '#/definitions/object.Product' + responses: + "200": + description: The Response object + schema: + $ref: '#/definitions/controllers.Response' /api/update-provider: post: tags: @@ -1620,10 +1743,10 @@ paths: schema: $ref: '#/definitions/object.Userinfo' definitions: - 1867.0xc00029b560.false: + 2015.0xc0000edb90.false: title: "false" type: object - 1901.0xc00029b590.false: + 2049.0xc0000edbc0.false: title: "false" type: object RequestForm: @@ -1637,9 +1760,9 @@ definitions: type: object properties: data: - $ref: '#/definitions/1867.0xc00029b560.false' + $ref: '#/definitions/2015.0xc0000edb90.false' data2: - $ref: '#/definitions/1901.0xc00029b590.false' + $ref: '#/definitions/2049.0xc0000edbc0.false' msg: type: string name: @@ -1653,9 +1776,9 @@ definitions: type: object properties: data: - $ref: '#/definitions/1867.0xc00029b560.false' + $ref: '#/definitions/2015.0xc0000edb90.false' data2: - $ref: '#/definitions/1901.0xc00029b590.false' + $ref: '#/definitions/2049.0xc0000edbc0.false' msg: type: string name: @@ -1710,6 +1833,10 @@ definitions: format: int64 forgetUrl: type: string + grantTypes: + type: array + items: + type: string homepageUrl: type: string logo: @@ -1875,6 +2002,41 @@ definitions: type: array items: type: string + object.Product: + title: Product + type: object + properties: + createdTime: + type: string + currency: + type: string + detail: + type: string + displayName: + type: string + image: + type: string + name: + type: string + owner: + type: string + price: + type: integer + format: int64 + providers: + type: array + items: + type: string + quantity: + type: integer + format: int64 + sold: + type: integer + format: int64 + state: + type: string + tag: + type: string object.Provider: title: Provider type: object @@ -2148,6 +2310,8 @@ definitions: type: string facebook: type: string + firstName: + type: string gender: type: string gitee: @@ -2182,10 +2346,15 @@ definitions: type: boolean isOnline: type: boolean + karma: + type: integer + format: int64 language: type: string lark: type: string + lastName: + type: string lastSigninIp: type: string lastSigninTime: