Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
Yukari316 committed Dec 22, 2021
0 parents commit 3d4698f
Show file tree
Hide file tree
Showing 10 changed files with 352 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/bin
/.idea
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# ms-graph-auth-helper

一个可以快速帮助获取Microsoft Graph API(OneDriver)令牌的小工具

~~在弄网盘API的时候觉得太麻烦了就搞了个这个~~

![ms-auth-run](https://user-images.githubusercontent.com/7535224/147150440-a5074cc7-ce73-4663-b9ee-09a323949666.png)

## 如何使用

在获取令牌时,请按照以下步骤操作

#### 注册新应用

- 打开[Azure应用管理面板](https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade)注册新的应用

- **受支持的帐户类型** 选项选择 **任何组织目录(任何 Azure AD 目录 - 多租户)中的帐户和个人 Microsoft 帐户(例如,Skype、Xbox)**

- 重定向URL(可选)中选择 **Web** 类型并将URL值设置为 **`http://localhost:11451/auth`**

#### 权限

- 切换至 **API权限** 选项卡点击 **添加权限**

- 选择 **Microsoft Graph** 分类

- 使用搜索功能找到并勾选以下权限:

- Files.Read

- Files.Read.All

- Files.ReadWrite

- Files.ReadWrite.All

- offline_access

- 点击 **添加权限** 完成授权

#### 应用程序(客户端) ID [Client Id]

- 切换至 **概述** 选项卡复制**应用程序(客户端) ID****自行保管**

#### 机密值[Client Secret]

- 切换至 **证书和密码** 选项卡

- 点击 **新建客户端密码** 并创建一个新的密钥

- 创建完成后复制密钥的值并**自行保管**

#### 启动工具按照提示完成令牌的获取
13 changes: 13 additions & 0 deletions browser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package main

import (
"os/exec"
)

func OpenBrowser(path string) error {
err := exec.Command("rundll32", "url.dll,FileProtocolHandler", path).Start()
if err != nil {
return err
}
return nil
}
22 changes: 22 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module ms-graph-auth-helper

go 1.17

require github.com/gin-gonic/gin v1.7.7

require (
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.13.0 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/go-playground/validator/v10 v10.4.1 // indirect
github.com/golang/protobuf v1.3.3 // indirect
github.com/json-iterator/go v1.1.9 // indirect
github.com/leodido/go-urn v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
github.com/ugorji/go/codec v1.1.7 // indirect
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
gopkg.in/yaml.v2 v2.2.8 // indirect
)
55 changes: 55 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
78 changes: 78 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package main

import (
"bufio"
"fmt"
"os"
"strings"
"time"
)

var console = bufio.NewReader(os.Stdin)

func main() {
initLog()
//重定向服务器
go StartServer()
fmt.Println("将跳转浏览器授权")
fmt.Println("请输入App的应用程序(客户端) ID [Client Id]")
clientId := readLine()
err := OpenBrowser(BuildMsAuthorizeUrl(clientId))
if err != nil {
fmt.Printf("启动浏览器时发生错误\r\n%s", err.Error())
}
fmt.Println()
clientCode := <-CodeCh
if clientCode != nil {
fmt.Printf("获取到code(%v)\r\n", len(*clientCode))
} else {
fmt.Println("获取code失败,请检查client_id和网络设置")
_ = readLine()
return
}
fmt.Println()
fmt.Println("请输入App的机密值[Client Secret]")
clientSecret := readLine()
fmt.Println()
tokenData, err := MsTokenRequest(clientId, clientSecret, *clientCode)
if err != nil {
fmt.Printf("获取token时发生错误\r\n%s", err.Error())
}
fmt.Printf("获取到token(%v)\r\n", len(tokenData.AccessToken))
fmt.Printf("获取到refresh-token(%v)\r\n", len(tokenData.RefreshToken))
saveData := TokenResult{
ClientId: clientId,
ClientCode: *clientCode,
Secret: clientSecret,
AccessToken: tokenData.AccessToken,
RefreshToken: tokenData.RefreshToken,
}
jsonBytes, err := saveData.Save()
if err != nil {
fmt.Println("保存token信息失败,请自行复制获取到的token")
time.Sleep(time.Second * 3)
fmt.Println(string(*jsonBytes))
}else{
fmt.Println("token信息已保存至工具根目录的result.json文件中")
}
fmt.Println("按下回车退出本工具")
readLine()
}

func readLine() (str string) {
str, _ = console.ReadString('\n')
str = strings.TrimSpace(str)
return
}

func initLog() {
fmt.Println("Ciallo~(∠・ω< )⌒☆")
fmt.Println("本工具将帮助你获取微软Graph的API的访问令牌,获取到的结果将保存到工具运行的目录下")
fmt.Println()
fmt.Println("请先保证使用本工具前已经在Microsoft Azure重创建了新的应用,并满足以下条件:")
fmt.Println("1.并授予了offline_access Files.Read Files.Read.All Files.ReadWrite Files.ReadWrite.All权限")
fmt.Println("2.重定向URL选择了(Web)类型,并设置值为(http://localhost:11451/auth)")
fmt.Println("3.在证书和密码选项卡中创建并保存了机密值(Client Secret)")
fmt.Println("请在确认以上条件后按回车继续")
_ = readLine()
}
10 changes: 10 additions & 0 deletions ms_token_resp_model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package main

type TokenResp struct {
TokenType string `json:"token_type"`
Scope string `json:"scope"`
ExpiresIn int `json:"expires_in"`
ExtExpiresIn int `json:"ext_expires_in"`
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
}
29 changes: 29 additions & 0 deletions redirect_server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package main

import (
"github.com/gin-gonic/gin"
)

// CodeCh 用于传输服务器返回的client-code
var CodeCh = make(chan *string)

func StartServer() {
gin.SetMode(gin.ReleaseMode)
router := gin.New()
router.GET("/auth", authMs)
err := router.Run(":11451")
if err != nil {
return
}
}

func authMs(c *gin.Context) {
code := c.Query("code")
if len(code) != 0 {
CodeCh <- &code
c.String(200, "获取client-code成功,请回到工具执行下一步操作\r\n\r\n%s" , code)
}else{
CodeCh <- nil
c.String(200, "获取client-code失败,请检查网络设置并再次运行")
}
}
33 changes: 33 additions & 0 deletions token_result.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package main

import (
"encoding/json"
"os"
)

type TokenResult struct {
ClientId string `json:"client-id"`
ClientCode string `json:"client-code"`
Secret string `json:"secret"`
AccessToken string `json:"access-token"`
RefreshToken string `json:"refresh-token"`
}

func (res *TokenResult) Save() (*[]byte, error) {
file, err := os.Create("result.json")
if err != nil {
return nil, err
}
defer func(file *os.File) {
_ = file.Close()
}(file)
if err != nil {
return nil, err
}
jsonBytes, err := json.MarshalIndent(res, ""," ")
if err != nil {
return nil, err
}
_, err = file.Write(jsonBytes)
return &jsonBytes, err
}
57 changes: 57 additions & 0 deletions util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package main

import (
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
)

func BuildMsAuthorizeUrl(clientId string) string {
u, _ := url.Parse("https://login.microsoftonline.com/common/oauth2/v2.0/authorize")
urlQuery := u.Query()
urlQuery.Set("client_id", clientId)
urlQuery.Set("redirect_uri", "http://localhost:11451/auth")
urlQuery.Set("response_type", "code")
u.RawQuery = urlQuery.Encode()
return fmt.Sprintf("%s&scope=offline_access+Files.Read+Files.Read.All+Files.ReadWrite+Files.ReadWrite.All", u.String())
}

func MsTokenRequest(clientId, clientSecret, clientCode string) (*TokenResp, error) {
data := url.Values{}
data.Set("client_id", clientId)
data.Set("redirect_uri", "http://localhost:11451/auth")
data.Set("client_secret", clientSecret)
data.Set("code", clientCode)
data.Set("grant_type", "authorization_code")
r, err := http.NewRequest(http.MethodPost,
"https://login.microsoftonline.com/common/oauth2/v2.0/token",
strings.NewReader(data.Encode()))
if err != nil {
return nil, err
}
r.Header.Add("Content-Type", "application/x-www-form-urlencoded")
client := &http.Client{}
resp, err := client.Do(r)
if resp.StatusCode != http.StatusOK {
errInfo := fmt.Sprintf("response http code %v", resp.StatusCode)
return nil, errors.New(errInfo)
}
defer func(Body io.ReadCloser) {
_ = Body.Close()
}(resp.Body)
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
tokenData := TokenResp{}
err = json.Unmarshal(body, &tokenData)
if err != nil {
return nil, err
}
return &tokenData, nil
}

0 comments on commit 3d4698f

Please sign in to comment.