Apes on both sides of the river crowed, the light boat has crossed the mountains

Authentication and authorization are most of the server system will involve a function module, especially in some large enterprises, as a result of the system are numerous, can’t log in any system needs to be individually related personnel input user name and password of the system, and in such circumstances, how to implement a login, Multi-system automatic login or automatic login after one authorization becomes an urgent problem to be solved.

Under JWT license

Before implementing JWT authorization, you need to understand the TOKEN authentication mechanism based on JWT. The token generated by THE JWT mechanism consists of three parts: header (header is an algorithm for generating signatures); Payload (payload contains specific information, such as the user name or token validity period); Signature (signature is generated by merging and hashing the contents of the first two parts with a secret key).

JWT format: header.payload-signature

Package main import ("encoding/json" "FMT" "github.com/dgrijalva/jwt-go" "log" "net/ HTTP ""time") // Set the key of JWT authentication signature Var users = map[string]string {"user1": "password1", "user2": "password2", } // The type Credentials struct {Password string 'json:" Password "' Username string 'json:" Username "'} Type Claims struct {Username string 'json:" Username "' jwt.StandardClaims} // func Login(w http.ResponseWriter, R *http.Request) {var creds Credentials // Check whether the Request Credentials are valid err := json.newdecoder (r.body).decode (&creds) if err! } // The legal user expectedPassword stored in the database, OK := users[cred.username] if! ok || expectedPassword ! Password {w.riteHeader (http.statusbadRequest) return} // If the authentication succeeds, Refresh token expiration date expirationTime := time.now ().add (time.minute * 5) // Write information to JWT authentication structures Claims := claims {Username: creds.Username, StandardClaims: jwt.StandardClaims{ ExpiresAt: Token := jwt.NewWithClaims(jwt.SigningMethodHS256, Claims) tokenString, err := token.SignedString(jwtKey) if err ! = nil {w.W riteHeader (HTTP StatusInternalServerError) return} / / will generate the token into the client (cookies or localStore) HTTP. SetCookie (w, &http.Cookie{ Name: "token", Value: tokenString, Expires: }} func Verify (w http.ResponseWriter, r *http.Request) { err := r.Cookie("token") if err ! = nil {// Cookie does not exist if err == http.ErrNoCookie {w.watriteHeader (http.statusUnauthorized) return} // Other cases W.white Header(http.statusbadRequest) return} tknStr := c. value Claims := &Claims{} TKN, err := jwt. parseClaims (tknStr, claims, func(token *jwt. token) (interface{}, error) { return jwtKey, nil }) if err ! = nil { if err == jwt.ErrSignatureInvalid { w.WriteHeader(http.StatusUnauthorized) return } w.WriteHeader(http.StatusBadRequest) return } if ! tkn.Valid { w.WriteHeader(http.StatusUnauthorized) return } w.Write([]byte(fmt.Sprintf("Welcome %s!" Func Refresh (w http.responsewriter, r * http.request) {// Obtain the token c from the cookie, err := r.Cookie("token") if err ! = nil { if err == http.ErrNoCookie { w.WriteHeader(http.StatusUnauthorized) return } Writeheader (http.statusbadRequest) return} // Construct token tknStr := c.value Claims := &Claims{} err := jwt.ParseWithClaims(tknStr, claims, func(token *jwt.Token) (interface{}, error) { return jwtKey, nil }) if err ! = nil { if err == jwt.ErrSignatureInvalid { w.WriteHeader(http.StatusUnauthorized) return } w.WriteHeader(http.StatusBadRequest) return } if ! Tkn. Valid {w.riteHeader (http.statusunauthorized) return} // Token authentication succeeds. Unix(Claims.ExpiresAt, 0).Sub(time.Now()) > 30*time.Second { w.WriteHeader(http.StatusBadRequest) return } expirationTime := time.Now().Add(time.Minute * 5) claims.ExpiresAt = expirationTime.Unix() token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) tokenStr, err := token.SignedString(jwtKey) if err ! = nil {w.W riteHeader (HTTP StatusInternalServerError) return} / / update the validity of the cookie time. HTTP SetCookie (w, & HTTP cookies {Name: "token", Value: tokenStr, Expires: expirationTime, }) } func main() { http.HandleFunc("/login", Login) http.HandleFunc("/verify", Verify) http.HandleFunc("/refresh", Refresh) log.Fatal(http.ListenAndServe(":9000", nil)) }Copy the code

Oauth2-based authorization

Before implementing oAuth2, we also need to understand the related concepts of oAuth2: Resource Owner, Resource Server, Client, Authorization Server, and User-Agent.

Resource owner: resource owner Resource server: service provider Server that stores user resources Client: user program that obtains resources Authentication server: service provider server that processes authentication User agent: program that users access clients, such as browsers

The login process is as follows: 1. When a user logs in to a third-party application, the application sends a request to the authentication server, stating that a user wants to perform an authorization operation, and at the same time stating who the user is and the callback URL after the user is authorized

2. The authentication server displays its own authorization interface to users

3. After the user performs an authorization operation, the authentication server generates an authorization code and redirects to the callback URL of the third party

4. After the third-party application gets the code, it sends it to the authentication server together with its own identity information (ID and password) on the platform to verify the request again, indicating that its identity is correct and the user has authorized me to exchange for access to user resources

5. The authentication server verifies the request information. If there is no problem, it generates the access_token to access the resource server and gives it to the third-party application

6. Third-party applications request resources from the resource server using the Access_token

7. The resource server validates the Access_token successfully and returns the response resource


Here is an example of oAuth2 authorized through Github

Front-end login authorization page

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index</title> </head> <body> <a href="https://github.com/login/oauth/authorize?client_id=49a31a8522020ac9ae05&redirect_uri=http://localhost:8080/oauth/r edirect"> Login with github </a> </body> </html>Copy the code

Server-side code handles logic

Oauth2. go package main import ("encoding/json" "FMT" "log" "net/ HTTP ") https://github.com/settings/applications/new const ( clientID = "xxx" clientSecret = "yyy" ) var httpClient = http.Client{} type OAuthAccessResponse struct { AccessToken string `json:"access_token"` } func HandleOauthRedirect(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if err ! = nil { log.Printf("could not parse query: %v", Err) w.merit Header(http.statusbadRequest)} code := R.fermValue ("code") // Obtain the authorization key from clientID, clientSecret, and code fmt.Sprintf("https://github.com/login/oauth/access_token?client_id=%s&client_secret=%s&code=%s", clientID, clientSecret, code) req, err := http.NewRequest(http.MethodPost, reqURL, nil) if err ! = nil { log.Printf("could not create HTTP request: %v", err) w.riteHeader (http.statusbadRequest)} // Set the returned format to json format req.header. Set("accept", "Application /json") // Send an HTTP request res, err := httpClient.Do(req) if err! = nil { log.Printf("could not send HTTP request: %v", Err) w.W riteHeader (HTTP StatusInternalServerError)} defer res. The Body. The Close () / / var parsing results t OAuthAccessResponse if err: = json.NewDecoder(res.Body).Decode(&t); err ! = nil { log.Printf("could not parse JSON response: %v", err) w.WriteHeader(http.StatusBadRequest) } w.Header().Set("Location", "/welcome.html? access_token="+t.AccessToken) w.WriteHeader(http.StatusFound) } func main() { fs := http.FileServer(http.Dir("./jwt")) http.Handle("/", fs) http.HandleFunc("/oauth/redirect", HandleOauthRedirect) http.ListenAndServe(":8080", nil) }Copy the code

Data request processing page after authentication

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>welcome</title> </head> <body> </body> <script> // Get access_token const query = window. The location. The search, the substring (1) the const token = query. The split (' access_token = ') [1] Fetch (' https://api.github.com/user '{headers: {/ / put a token in the Authorization Header: 'token ' + token } }) .then(res => res.json()) .then(res => { const nameNode = document.createTextNode(`Welcome, ${res.name}`) document.body.appendChild(nameNode) }) </script> </html>Copy the code

summary

This article mainly explains the implementation of JWT and OAuth2 authorization schemes based on GO. As long as you understand the relevant concepts, it should not be very difficult to implement, and I hope to help people in need.

Resources 1:blog.csdn.net/neweastsun/… Resources 2:razeencheng.com/post/oauth2…