Skip to content

Commit

Permalink
support device flow mode
Browse files Browse the repository at this point in the history
  • Loading branch information
Laceyoo committed Dec 1, 2023
1 parent 5a4c186 commit 21b66a1
Show file tree
Hide file tree
Showing 10 changed files with 908 additions and 13 deletions.
72 changes: 72 additions & 0 deletions controller/oauth2_device_flow.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package controller

import (
"fmt"
"github.com/ECNU/Open-OAuth2Playground/g"
"github.com/ECNU/Open-OAuth2Playground/models"
"github.com/gin-gonic/gin"
"net/http"
"strconv"
"time"
)

type ReqDeviceData struct {
ClientId string `json:"client_id"`
Code string `json:"code"`
ResponseType string `json:"response_type"`
ExpiresIn int `json:"expires_in"`
}

func deviceFlow(c *gin.Context) {
reqData := ReqDeviceData{}
if err := c.Bind(&reqData); err != nil {
c.JSON(http.StatusOK, handleError(err.Error()))
return
}

method := "POST"
apiAddr := g.Config().Endpoints.Token

Code := reqData.Code
clientId := reqData.ClientId
ResponseType := reqData.ResponseType
ExpiresIn := reqData.ExpiresIn
body := fmt.Sprintf("code=%s&client_id=%s&response_type=%s", Code, clientId, ResponseType)

header := make(map[string]string)
header["Content-Type"] = "application/x-www-form-urlencoded"
header["Content-Length"] = strconv.Itoa(len(body))

timeoutChan := time.After(time.Duration(ExpiresIn) * time.Second) // 设置expires_in秒后超时
dataChan := make(chan models.Resp)

// 启动一个协程循环检测token是否可用
go func() {
for {
res, err := models.HandleRequest(method, apiAddr, g.UserAgent, body, g.Config().Timeout, header)
if err != nil {
c.JSON(http.StatusOK, handleError(err.Error()))
return
}
// 检查返回值中是否包含token
if rawJsonMap, ok := res.RawJson.(map[string]interface{}); ok {
if _, tokenAvailable := rawJsonMap["access_token"]; tokenAvailable {
dataChan <- res
return
}
} else {
fmt.Println("res.RawJson不是map格式")
}
time.Sleep(1000 * time.Millisecond) // 每隔1秒轮询
}
}()

// 已获取token或超时
select {
case res := <-dataChan:
c.JSON(http.StatusOK, handleSuccess(res))
//return res, nil
case <-timeoutChan:
c.JSON(http.StatusOK, handleError("user code expired"))
}
}
1 change: 1 addition & 0 deletions controller/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ func Routes(r *gin.Engine) {
playground := r.Group(g.Config().Http.RouteBase + "v1")
playground.Use(IPLimitCheck)
playground.Use(NoCache())
playground.POST("/oauth2/device_flow", deviceFlow)
playground.POST("/oauth2/client_credentials", clientCredentials)
playground.POST("/oauth2/password", passwordMode)
playground.POST("/oauth2/authorization_code", exchangeTokenByCode)
Expand Down
5 changes: 5 additions & 0 deletions front-standalone/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,32 @@
"dependencies": {
"@element-plus/icons-vue": "^1.1.4",
"@highlightjs/vue-plugin": "^2.1.0",
"@types/crypto-js": "^4.2.1",
"@typescript-eslint/eslint-plugin": "^5.59.8",
"@typescript-eslint/parser": "^5.59.8",
"@vue/cli-plugin-typescript": "^5.0.8",
"@vue/eslint-config-typescript": "^11.0.3",
"axios": "^0.27.2",
"core-js": "^3.30.2",
"crypto-js": "^4.2.0",
"eslint-plugin-vue": "^9.14.1",
"highlight.js": "^11.8.0",
"less": "^4.1.3",
"less-loader": "^7.3.0",
"qrcode": "^1.5.3",
"qs": "^6.11.2",
"typescript": "^5.0.4",
"vue": "^3.3.4",
"vue-clipboard3": "^2.0.0",
"vue-router": "^4.2.2",
"vuex": "^4.1.0",
"vuex-persistedstate": "^4.1.0",
"webpack": "^5.85.0"
},
"devDependencies": {
"@babel/eslint-parser": "^7.21.8",
"@types/node": "^20.3.1",
"@types/qrcode": "^1.5.5",
"@types/qs": "^6.9.7",
"@vue/cli-plugin-babel": "^5.0.8",
"@vue/cli-plugin-eslint": "^5.0.8",
Expand Down
9 changes: 8 additions & 1 deletion front-standalone/src/api/playground.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,11 @@ export const fetchACTokenByClient = (data) => {
/** Password */
export const fetchACTokenByPassword = (data) => {
return http.post<Result>("/oauth2/password", data);
};
};

/** Device Flow */
/** Step 2 */
/** Get access_token with device_code */
export const fetchACTokenByDevice = (data) => {
return http.post<Result>("/oauth2/device_flow", data);
};
15 changes: 10 additions & 5 deletions front-standalone/src/store/index.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import { createStore } from "vuex"
import createPersistedState from 'vuex-persistedstate';


const store = createStore({
state() {
return {
backendUrl: 'http://localhost:80',
authServerUrl: ''
authServerUrl: '',
grantTypes: "1"
}
},
mutations: {
setBackEndUrl(state, v) {
state.backendUrl = v
}
}
},
setGrantTypes(state, v) {
state.grantTypes = v;
},
},
plugins: [createPersistedState()],
})


export default store
export default store
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ async function handleGetToken() {
fetchACToken(dataObject).then(({code, msg, data}) => {
if(code === 0){
const {request, response, rawjson, example} = data;
const {access_token, refresh_token} = rawjson || {};;
const {access_token, refresh_token} = rawjson || {};
currentToken.value = access_token??"Uncertain";
currentRefreshToken.value = refresh_token??"Uncertain";
s3CurrentToken.value = access_token??"Uncertain";
Expand Down Expand Up @@ -311,11 +311,10 @@ function formatJson(jsonStr) {
// 格式化 JSON 内容
try {
let resStr = JSON.stringify(JSON.parse(jsonStr), null, ' ');
// console.log(resStr);
return resStr;
} catch (error) {
// 解析失败,返回原始内容
console.log('格式化json失败');
console.error('格式化json失败');
return jsonStr;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ function formatJson(jsonStr) {
return resStr;
} catch (error) {
// 解析失败,返回原始内容
console.log('格式化json失败');
console.error('格式化json失败');
return jsonStr;
}
}
Expand Down
Loading

0 comments on commit 21b66a1

Please sign in to comment.