table of Contents
1. What is the JWT
Web Token JSON (the JWT) is the most popular cross-domain authentication solutions. Simply put, OAuth is a kind of authorization mechanisms. Tell the owner of the data system, agreed to authorize third-party applications into the system, access to these data. System to produce a short-term order entry (token), is used instead of the password for using third party applications. .
Traditional authorization and authentication, for the persistent session data into the database or file persistence layer or the like, dependent on the data and the authorization verification persistence layer . In this way, the structure 维护成本大
, implement 单点登录较为复杂
, and not distributed architecture 无法支持横向扩展
, 风险较大
(if persistence layer fails, the entire certification system will hang up).
JWT is no need to persist session data is encrypted signature way to achieve the user identity authentication and authorization, a good solution 跨域身份验证
, 分布式session共享
, 单点登录
and 横向扩展
other issues.
Two. JWT standards
JWT consists of three parts, i.e. 头部
, 负载
the 签名
. Token format token=头部+'.'+载荷+'.'+签名
.
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Nzg0MDQ5OTUsImlhdCI6MTU3ODQwMTM5NX0.waG8rvOZLM2pKDeKg7frMKlV8lAty1Og5LDjrVMJRsI"}
1. Header: for explaining cryptographically signed and the like, of the following types json obtained after base64 encoded JWT head.
{
"typ": "JWT",
"alg": "HS256"
}
2. Payload: standard defines seven fields, load json obtained after base64 encoded JWT load.
{
iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号
}
Example:
{
"sub": "1",
"iss": "http://localhost:8000/user/sign_up",
"iat": 1451888119,
"exp": 1454516119,
"nbf": 1451888119,
"jti": "37c107e4609ddbcc9c096ea5ee76c667"
}
3.Signature: a header and a payload with the connection number, together with a string key, an encryption algorithm obtained through the head declaration encrypted signature '.'.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
III. Analysis of the core code
1. Data Structure
// A JWT Token. Different fields will be used depending on whether you're
// creating or parsing/verifying a token.
type Token struct {
Raw string // The raw token. Populated when you Parse a token
Method SigningMethod // The signing method used or to be used
Header map[string]interface{} // (头部)The first segment of the token
Claims Claims // (负载)The second segment of the token
Signature string // (签名)The third segment of the token. Populated when you Parse a token
Valid bool // Is the token valid? Populated when you Parse/Verify a token
}
// Structured version of Claims Section, as referenced at
// https://tools.ietf.org/html/rfc7519#section-4.1
// See examples for how to use this with your own claim types
type StandardClaims struct {
Id string `json:"jti,omitempty"` //编号
Subject string `json:"sub,omitempty"` //主题
Issuer string `json:"iss,omitempty"` //签发人
Audience string `json:"aud,omitempty"` //受众
ExpiresAt int64 `json:"exp,omitempty"` //过期时间
IssuedAt int64 `json:"iat,omitempty"` //签发时间
NotBefore int64 `json:"nbf,omitempty"` //生效时间
}
2. Generate Token
var(
key []byte = []byte("This is secret!")
)
// 产生json web token
func GenToken() string {
claims := &jwt.StandardClaims{
NotBefore: int64(time.Now().Unix()),
ExpiresAt: int64(time.Now().Unix() + 1000),
Issuer: "Bitch",
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
ss, err := token.SignedString(key)
if err != nil {
logs.Error(err)
return ""
}
return ss
}
3. Verify Token
// 校验token是否有效
func CheckToken(token string) bool {
_, err := jwt.Parse(token, func(*jwt.Token) (interface{}, error) {
return key, nil
})
if err != nil {
fmt.Println("parase with claims failed.", err)
return false
}
return true
}
IV. Examples of login authorization
handler/auth.go
package handler
import (
"fmt"
"github.com/dgrijalva/jwt-go"
"github.com/dgrijalva/jwt-go/request"
"net/http"
)
const (
SecretKey = "ODcyNDYsIMzY0N"
)
func ValidateTokenMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
token, err := request.ParseFromRequest(r, request.AuthorizationHeaderExtractor,
func(token *jwt.Token) (interface{}, error) {
return []byte(SecretKey), nil
})
if err == nil {
if token.Valid {
next(w, r)
} else {
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprint(w, "Token is not valid")
}
} else {
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprint(w, "Unauthorized access to this resource")
}
}
handler/account.go
package handler
import (
"encoding/json"
"fmt"
"github.com/dgrijalva/jwt-go"
"log"
"net/http"
"strings"
"time"
)
func fatal(err error) {
if err != nil {
log.Fatal(err)
}
}
type UserCredentials struct {
Username string `json:"username"`
Password string `json:"password"`
}
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Username string `json:"username"`
Password string `json:"password"`
}
type Response struct {
Data string `json:"data"`
}
type Token struct {
Token string `json:"token"`
}
func LoginHandler(w http.ResponseWriter, r *http.Request) {
var user UserCredentials
err := json.NewDecoder(r.Body).Decode(&user)
if err != nil {
w.WriteHeader(http.StatusForbidden)
fmt.Fprint(w, "Error in request")
return
}
if strings.ToLower(user.Username) != "admin" {
if user.Password != "123456" {
w.WriteHeader(http.StatusForbidden)
fmt.Fprint(w, "Invalid credentials")
return
}
}
// 创建Token
token := jwt.New(jwt.SigningMethodHS256)
claims := make(jwt.MapClaims)
claims["exp"] = time.Now().Add(time.Hour * time.Duration(1)).Unix()
claims["iat"] = time.Now().Unix()
token.Claims = claims
//if err != nil {
// w.WriteHeader(http.StatusInternalServerError)
// fmt.Fprintln(w, "Error extracting the key")
// fatal(err)
//}
tokenString, err := token.SignedString([]byte(SecretKey))
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintln(w, "Error while signing the token")
fatal(err)
}
response := Token{tokenString}
JsonResponse(response, w)
}
func FundHandler(w http.ResponseWriter, r *http.Request) {
response := Response{"账户余额:1000W"}
JsonResponse(response, w)
}
func JsonResponse(response interface{}, w http.ResponseWriter) {
obj, err := json.Marshal(response)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
w.Write(obj)
}
main.go
import (
"github.com/codegangsta/negroni"
"log"
"net/http"
"proxy/handler"
)
func Server() {
http.HandleFunc("/login", handler.LoginHandler)
http.Handle("/data", negroni.New(
negroni.HandlerFunc(handler.ValidateTokenMiddleware), //中间件
negroni.Wrap(http.HandlerFunc(handler.FundHandler)),
))
log.Println("服务已启动...")
http.ListenAndServe(":8080", nil)
}
func main() {
Server()
}
Five. JWT use
JWT client receives the server returns, can be stored in Cookie
it, can also be stored in localStorage
.
Thereafter, each time the client and server communications, must bring the JWT. You can put it inside Cookie sent automatically, but this 不能跨域
. So a better approach is to put the HTTP request header Authorization
field inside (or on the body of the POST request data inside).
Authorization: Bearer <token>
Six. JWT Notes
- JWT is not encrypted by default, but can be encrypted. After generating the original token can be used to change the token to encrypt again.
- JWT not only for authentication, may be used to exchange information. Make good use of JWT helps reduce the number of server requests the database.
- JWT biggest drawback is that the server does not save session state, JWT once issued, will remain in effect in the period.
- JWT should not be set too long a period, authentication information, so once information leaks, anyone can get a token of all rights.
- JWT order to reduce the risk of data theft and theft, JWT is recommended to use an encrypted HTTPS protocol for transmission.
Reference:
http://www.ruanyifeng.com/blog/2019/04/oauth_design.html关于OAuth2.0
https://blog.csdn.net/wangshubo1989/article/details/74529333
https://blog.csdn.net/idwtwt/ Article This article was / the Details / 80,865,209
https://baijiahao.baidu.com/s?id=1608021814182894637&wfr=spider&for=pc
http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html