up
This commit is contained in:
@@ -1,8 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"chat/services/board"
|
||||||
"encoding/base64"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -16,29 +15,21 @@ import (
|
|||||||
"github.com/golang-jwt/jwt"
|
"github.com/golang-jwt/jwt"
|
||||||
"github.com/google/go-github/v50/github"
|
"github.com/google/go-github/v50/github"
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
"golang.org/x/oauth2"
|
|
||||||
"gorm.io/driver/mysql"
|
"gorm.io/driver/mysql"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
var db *gorm.DB
|
var db *gorm.DB
|
||||||
var jwtSecret = []byte("JWT_SECRET")
|
var jwtSecret = []byte("JWT_SECRET")
|
||||||
var oauthConf *oauth2.Config
|
|
||||||
|
|
||||||
func main() {
|
func init() {
|
||||||
err := godotenv.Load()
|
err := godotenv.Load()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error loading .env file")
|
log.Fatal("Error loading .env file")
|
||||||
}
|
}
|
||||||
oauthConf = &oauth2.Config{
|
}
|
||||||
ClientID: os.Getenv("GITHUB_CLIENT_ID"),
|
|
||||||
ClientSecret: os.Getenv("GITHUB_CLIENT_SECRET"),
|
|
||||||
// Scopes: []string{"read:user", "user:email"},
|
|
||||||
Endpoint: oauth2.Endpoint{
|
|
||||||
AuthURL: "https://github.com/login/oauth/authorize",
|
|
||||||
TokenURL: "https://github.com/login/oauth/access_token",
|
|
||||||
}}
|
|
||||||
|
|
||||||
|
func main() {
|
||||||
initDB()
|
initDB()
|
||||||
|
|
||||||
router := gin.Default()
|
router := gin.Default()
|
||||||
@@ -53,27 +44,12 @@ func main() {
|
|||||||
AllowCredentials: true,
|
AllowCredentials: true,
|
||||||
}))
|
}))
|
||||||
router.GET("/", func(ctx *gin.Context) { ctx.Writer.WriteString("hello world") })
|
router.GET("/", func(ctx *gin.Context) { ctx.Writer.WriteString("hello world") })
|
||||||
router.GET("/auth/github", githubLoginHandler)
|
router.GET("/auth/idt", board.IdentityHandler)
|
||||||
// router.POST("/auth/signin/sso", )
|
router.POST("/auth/signin/sso", board.SSOHandler)
|
||||||
|
|
||||||
router.Run(":8000")
|
router.Run(":8000")
|
||||||
}
|
}
|
||||||
|
|
||||||
func githubLoginHandler(c *gin.Context) {
|
|
||||||
state := generateState()
|
|
||||||
|
|
||||||
session := sessions.Default(c)
|
|
||||||
session.Set("state", state)
|
|
||||||
if err := session.Save(); err != nil {
|
|
||||||
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
url := oauthConf.AuthCodeURL("state")
|
|
||||||
log.Println(url)
|
|
||||||
c.Redirect(http.StatusFound, url)
|
|
||||||
}
|
|
||||||
|
|
||||||
func initDB() {
|
func initDB() {
|
||||||
dsn := os.Getenv("MYSQL_DSN")
|
dsn := os.Getenv("MYSQL_DSN")
|
||||||
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
@@ -92,24 +68,6 @@ func initDB() {
|
|||||||
log.Println("Database connection established")
|
log.Println("Database connection established")
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateState() string {
|
|
||||||
return generateRandomString(20)
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateCode() string {
|
|
||||||
return generateRandomString(20)
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateRandomString(length int) string {
|
|
||||||
byteArr := make([]byte, length)
|
|
||||||
_, err := rand.Read(byteArr)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Error generating random string:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return base64.URLEncoding.EncodeToString(byteArr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func storeStateToDB(state, code string) error {
|
func storeStateToDB(state, code string) error {
|
||||||
query := "INSERT INTO oauth_state (state, code) VALUES (?, ?)"
|
query := "INSERT INTO oauth_state (state, code) VALUES (?, ?)"
|
||||||
err := db.Exec(query, state, code).Error
|
err := db.Exec(query, state, code).Error
|
||||||
|
|||||||
@@ -1,76 +1,88 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="!accessToken">
|
<div>
|
||||||
<button @click="">Login with GitHub</button>
|
<button @click="handleGithubLogin">Login with GitHub</button>
|
||||||
</div>
|
|
||||||
<div v-else>
|
|
||||||
<p>Access Token: {{ accessToken }}</p>
|
|
||||||
<button @click="logout">Logout</button>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import { reactive } from 'vue';
|
import { reactive,onMounted } from 'vue';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
export default {
|
const auth = reactive({
|
||||||
setup() {
|
type: "github",
|
||||||
|
redirectUrl: null,
|
||||||
|
code: null,
|
||||||
|
state: null,
|
||||||
|
});
|
||||||
|
|
||||||
const auth = reactive({
|
const handleGithubLogin = async()=> {
|
||||||
type: "github",
|
try {
|
||||||
redirectUrl: null,
|
const response = await axios.get('http://localhost:8000/auth/idt')
|
||||||
code: null,
|
const redirectUrl = response.data.redirectUri
|
||||||
state: null,
|
auth.state = response.data.state
|
||||||
});
|
auth.redirectUrl = redirectUrl
|
||||||
|
localStorage.setItem("state",response.data.state)
|
||||||
|
console.log("state:",response.data.state,"url:",response.data.redirectUri)
|
||||||
|
window.location.href = redirectUrl
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Function to handle GitHub login button click
|
const handleCallback = async () => {
|
||||||
const handleGithubLogin = async () => {
|
// const code = this.$route.query.code
|
||||||
try {
|
// const status = this.$route.query.status
|
||||||
// Send a GET request to /auth/github to get the redirect URL
|
const urlParams = new URLSearchParams(window.location.search)
|
||||||
const response = await axios.get('/auth/github')
|
const code = urlParams.get('code')
|
||||||
auth.redirectUrl = response.data.redirectUrl
|
const status = urlParams.get('state')
|
||||||
auth.state = response.data.state
|
try {
|
||||||
|
const response = await axios.post('/auth/signin/sso', {
|
||||||
window.location.href = state.redirectUrl
|
code,
|
||||||
} catch (error) {
|
status
|
||||||
console.error(error)
|
})
|
||||||
}
|
const jwt = response.data.jwt
|
||||||
};
|
localStorage.setItem('jwt', jwt)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
const handleCallback = async () => {
|
if (error.response.status != 200) {
|
||||||
// const code = this.$route.query.code
|
console.log('授权失败')
|
||||||
// const status = this.$route.query.status
|
}
|
||||||
const urlParams = new URLSearchParams(window.location.search)
|
}
|
||||||
const code = urlParams.get('code')
|
|
||||||
const status = urlParams.get('state')
|
|
||||||
try {
|
|
||||||
const response = await axios.post('/auth/signin/sso', {
|
|
||||||
code,
|
|
||||||
status
|
|
||||||
})
|
|
||||||
const jwt = response.data.jwt
|
|
||||||
localStorage.setItem('jwt', jwt)
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
if (error.response.status != 200) {
|
|
||||||
console.log('授权失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const logout = () => {
|
|
||||||
localStorage.setItem('jwt','');
|
|
||||||
};
|
|
||||||
|
|
||||||
// // 监听 URL 变化,处理从 GitHub 授权页面回调回来的 code 参数
|
|
||||||
// const handleUrlChange = () => {
|
|
||||||
// const urlParams = new URLSearchParams(window.location.search);
|
|
||||||
// const code = urlParams.get('code');
|
|
||||||
// if (code) {
|
|
||||||
// handleCallback(code);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// window.addEventListener('load', handleUrlChange);
|
|
||||||
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
async function getToken() {
|
||||||
|
try {
|
||||||
|
const url = new URL(window.location.href)
|
||||||
|
const code = url.searchParams.get('code')
|
||||||
|
const state = url.searchParams.get('state')
|
||||||
|
const postData = new URLSearchParams({
|
||||||
|
code: code,
|
||||||
|
state: state
|
||||||
|
})
|
||||||
|
const jwtResponse = await axios.post('http://localhost:8000/auth/signin/sso', postData)
|
||||||
|
const jwt = jwtResponse.data.jwt
|
||||||
|
localStorage.setItem('jwt', jwt)
|
||||||
|
console.log("jwt:",jwtResponse)
|
||||||
|
// window.location.href = '/'
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const logout = () => {
|
||||||
|
localStorage.setItem('jwt','');
|
||||||
|
};
|
||||||
|
|
||||||
|
// // 监听 URL 变化,处理从 GitHub 授权页面回调回来的 code 参数
|
||||||
|
// const handleUrlChange = () => {
|
||||||
|
// const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
// const code = urlParams.get('code');
|
||||||
|
// if (code) {
|
||||||
|
// handleCallback(code);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// window.addEventListener('load', handleUrlChange);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getToken()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -2,6 +2,8 @@ package board
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -13,16 +15,7 @@ import (
|
|||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var ()
|
||||||
oauthConf = &oauth2.Config{
|
|
||||||
ClientID: os.Getenv("GITHUB_CLIENT_ID"),
|
|
||||||
ClientSecret: os.Getenv("GITHUB_CLIENT_SECRET"),
|
|
||||||
// Scopes: []string{"read:user", "user:email"},
|
|
||||||
Endpoint: oauth2.Endpoint{
|
|
||||||
AuthURL: "https://github.com/login/oauth/authorize",
|
|
||||||
TokenURL: "https://github.com/login/oauth/access_token",
|
|
||||||
}}
|
|
||||||
)
|
|
||||||
|
|
||||||
type SignIn struct {
|
type SignIn struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
@@ -40,9 +33,55 @@ type SignUp struct {
|
|||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func generateState() string {
|
||||||
|
return generateRandomString(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateCode() string {
|
||||||
|
return generateRandomString(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateRandomString(length int) string {
|
||||||
|
byteArr := make([]byte, length)
|
||||||
|
_, err := rand.Read(byteArr)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error generating random string:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return base64.URLEncoding.EncodeToString(byteArr)
|
||||||
|
}
|
||||||
|
func IdentityHandler(c *gin.Context) {
|
||||||
|
state := generateState()
|
||||||
|
|
||||||
|
session := sessions.Default(c)
|
||||||
|
session.Set("state", state)
|
||||||
|
if err := session.Save(); err != nil {
|
||||||
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
oauthConf := &oauth2.Config{
|
||||||
|
ClientID: os.Getenv("GITHUB_CLIENT_ID"),
|
||||||
|
ClientSecret: os.Getenv("GITHUB_CLIENT_SECRET"),
|
||||||
|
RedirectURL: "http://localhost:5173/",
|
||||||
|
// Scopes: []string{"read:user", "user:email"},
|
||||||
|
Endpoint: oauth2.Endpoint{
|
||||||
|
AuthURL: "https://github.com/login/oauth/authorize",
|
||||||
|
TokenURL: "https://github.com/login/oauth/access_token",
|
||||||
|
}}
|
||||||
|
url := oauthConf.AuthCodeURL(state)
|
||||||
|
log.Println(url)
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"state": state,
|
||||||
|
"redirectUri": url,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func SSOHandler(c *gin.Context) {
|
func SSOHandler(c *gin.Context) {
|
||||||
signin := SSOSignIn{}
|
signin := SSOSignIn{}
|
||||||
|
if err := c.BindQuery(&signin); err != nil {
|
||||||
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Unmashal request body."})
|
||||||
|
return
|
||||||
|
}
|
||||||
session := sessions.Default(c)
|
session := sessions.Default(c)
|
||||||
savedState := session.Get("state")
|
savedState := session.Get("state")
|
||||||
if savedState == nil || savedState.(string) != signin.State {
|
if savedState == nil || savedState.(string) != signin.State {
|
||||||
@@ -50,6 +89,14 @@ func SSOHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
oauthConf := &oauth2.Config{
|
||||||
|
ClientID: os.Getenv("GITHUB_CLIENT_ID"),
|
||||||
|
ClientSecret: os.Getenv("GITHUB_CLIENT_SECRET"),
|
||||||
|
// Scopes: []string{"read:user", "user:email"},
|
||||||
|
Endpoint: oauth2.Endpoint{
|
||||||
|
AuthURL: "https://github.com/login/oauth/authorize",
|
||||||
|
TokenURL: "https://github.com/login/oauth/access_token",
|
||||||
|
}}
|
||||||
// 使用 code 换取 token
|
// 使用 code 换取 token
|
||||||
token, err := oauthConf.Exchange(context.Background(), signin.Code)
|
token, err := oauthConf.Exchange(context.Background(), signin.Code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user