This commit is contained in:
Sakurasan
2023-04-10 02:27:52 +08:00
parent 31341cf5bf
commit 0348d383a3
11 changed files with 123 additions and 318 deletions

View File

@@ -11,6 +11,8 @@ import (
"time"
"github.com/gin-contrib/cors"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt"
"github.com/google/go-github/v50/github"
@@ -42,6 +44,9 @@ func main() {
router := gin.Default()
store := cookie.NewStore([]byte("secret"))
router.Use(sessions.Sessions("my-session", store))
router.Use(cors.New(cors.Config{
AllowOrigins: []string{"*"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD"},
@@ -56,15 +61,14 @@ func main() {
}
func githubLoginHandler(c *gin.Context) {
// state := generateState()
// code := generateCode()
state := generateState()
// err := storeStateToDB(state, code)
// if err != nil {
// log.Println("Error storing state to DB:", err)
// c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"message": "Internal server error"})
// return
// }
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)
@@ -72,30 +76,27 @@ func githubLoginHandler(c *gin.Context) {
}
func githubCallbackHandler(c *gin.Context) {
state := c.Query("state")
code := c.Query("code")
log.Println(state, code)
// if !verifyState(state, code) {
// c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"message": "Invalid state"})
// return
// }
code, state := c.Query("code"), c.Query("state")
session := sessions.Default(c)
savedState := session.Get("state")
if savedState == nil || savedState.(string) != state {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid state parameter."})
return
}
// 使用 code 换取 token
token, err := oauthConf.Exchange(context.Background(), code)
if err != nil {
// c.String(http.StatusBadRequest, "授权失败: %s", err.Error())
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": fmt.Errorf("授权失败: %s", err.Error())})
return
}
log.Println("token:", token)
// 使用 token 获取 GitHub 用户信息
// client := github.NewClient(oauthConf.Client(context.Background(), token))
client := github.NewClient(oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(token)))
client := github.NewClient(oauthConf.Client(context.Background(), token))
// client := github.NewClient(oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(token)))
user, _, err := client.Users.Get(c.Request.Context(), "")
if err != nil {
// c.String(http.StatusInternalServerError, "获取用户信息失败: %s", err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": fmt.Errorf("获取用户信息失败: %s", err.Error())})
return
}
@@ -111,6 +112,7 @@ func githubCallbackHandler(c *gin.Context) {
log.Println(user.GetEmail(), user.GetName(), user.GetID(), user.GetAvatarURL())
// 处理用户信息
c.JSON(http.StatusOK, gin.H{
"id": user.ID,
"login": user.Login,
"name": user.Name,
"email": user.Email,
@@ -203,19 +205,21 @@ func storeUserToDB(user *github.User) error {
return nil
}
func generateJWTToken(userID int64) (string, error) {
// Generate a signed JWT containing the user ID as a claim.
func generateJWT(userID int64) (string, error) {
token := jwt.New(jwt.SigningMethodHS256)
claims := jwt.MapClaims{
"sub": userID,
"exp": time.Now().Add(24 * time.Hour).Unix(),
}
token.Claims = claims
claims := token.Claims.(jwt.MapClaims)
claims["user"] = userID
claims["exp"] = time.Now().Add(time.Hour * 24).Unix()
jwtToken, err := token.SignedString(jwtSecret)
signedToken, err := token.SignedString(jwtSecret)
if err != nil {
return "", err
}
return jwtToken, nil
return signedToken, nil
}
func verifyJWTToken(tokenString string) {
@@ -242,3 +246,48 @@ func verifyJWTToken(tokenString string) {
fmt.Println("Invalid token.")
}
}
// Middleware to require authentication via JWT.
func requireAuth() gin.HandlerFunc {
return func(c *gin.Context) {
tokenString := c.GetHeader("Authorization")
if tokenString == "" {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Missing Authorization header."})
return
}
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return jwtSecret, nil
})
if err != nil {
if err == jwt.ErrSignatureInvalid {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid token signature."})
return
}
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid token."})
return
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok || !token.Valid {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid token claims."})
return
}
userID, ok := claims["sub"].(float64)
if !ok {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid subject claim type."})
return
}
// Use the userID to look up the user in your database or perform other authorization logic.
// ...
// If authorized, set the user ID on the Gin context for use by downstream handlers.
c.Set("userID", int64(userID))
c.Next()
}
}