本人是做java开发的,最近突然对go提起了兴趣,看了n篇大牛文章后,所谓好好学习天天向上,故有了本篇:
(一)整合redis
"github.com/garyburd/redigo/redis"
举个最简单的例子,存储发送的验证码:
redisutil.go
package redis
import (
"errors"
"github.com/garyburd/redigo/redis"
"math"
"time"
)
type Redis struct {
redisCli *redis.Pool
maxIdle int
maxActive int
maxIdleTimeout time.Duration
maxTimeout time.Duration
lazyLimit bool
maxSize int
}
func (r *Redis) getRedisConn() redis.Conn {
rc := r.redisCli.Get()
return rc
}
func (r *Redis) GetAllKeys() []string {
rc := r.getRedisConn()
defer rc.Close()
keys, err := redis.Strings(rc.Do("KEYS", "*"))
if err != nil {
return make([]string, 0)
}
return keys
}
func (r *Redis) Get(key string, timeout int) (string, error) {
start := time.Now()
for {
res, err := r.GetNoWait(key)
if err != nil {
return "", err
} else if res == "" {
if timeout != -1 {
lasted := time.Now().Sub(start)
if r.maxTimeout > lasted {
t1 := r.maxTimeout
t2 := time.Duration(timeout)*time.Second - lasted
time.Sleep(time.Duration(math.Min(float64(t1), float64(t2))))
} else {
return "", errors.New("GET timeout")
}
} else {
time.Sleep(r.maxTimeout)
}
} else {
return res, nil
}
}
}
func (r *Redis) GetNoWait(key string) (string, error) {
rc := r.getRedisConn()
defer rc.Close()
res, err := redis.String(rc.Do("LPOP", key))
if err != nil {
return "", err
}
return res, nil
}
func (r *Redis) Put(key string, value string, timeout int) (int, error) {
start := time.Now()
for {
res, err := r.PutNoWait(key, value)
if err != nil {
return 0, err
} else if res == -1 {
if timeout != -1 {
lasted := time.Now().Sub(start)
if r.maxTimeout > lasted {
t1 := r.maxTimeout
t2 := time.Duration(timeout)*time.Second - lasted
time.Sleep(time.Duration(math.Min(float64(t1), float64(t2))))
} else {
return 0, errors.New("PUT timeout")
}
} else {
time.Sleep(r.maxTimeout)
}
} else {
return res, nil
}
}
}
func (r *Redis) PutNoWait(key string, value string) (int, error) {
rc := r.getRedisConn()
defer rc.Close()
if r.Full(key) {
return -1, nil
}
res, err := redis.Int(rc.Do("RPUSH", key, value))
if err != nil {
return 0, err
}
return res, nil
}
func (r *Redis) QSize(key string) int {
rc := r.getRedisConn()
defer rc.Close()
res, err := redis.Int(rc.Do("LLEN", key))
if err != nil {
return -1
}
return res
}
func (r *Redis) Empty(key string) bool {
rc := r.getRedisConn()
defer rc.Close()
res, err := redis.Int(rc.Do("LLEN", key))
if err != nil {
return false
}
if res == 0 {
return true
}
return false
}
func (r *Redis) Full(key string) bool {
if r.maxSize != 0 && r.QSize(key) >= r.maxSize {
return true
}
return false
}
redisinterface.go
package redis
import (
"github.com/garyburd/redigo/redis"
"time"
)
type RedisFatherInterface interface {
GetAllKeys() []string
}
type ListInterface interface {
RedisFatherInterface
GetNoWait(key string) (string, error)
Get(key string, timeout int) (string, error)
Put(key string, value string, timeout int) (int, error)
PutNoWait(key string, value string) (int, error)
QSize(key string) int
Empty(key string) bool
Full(key string) bool
}
type RedisInterface interface {
ListInterface
}
func ProducetRedis() (RedisInterface, error) {
redisObj := &Redis{
maxIdle: 100,
maxActive: 130,
maxIdleTimeout: time.Duration(60) * time.Second,
maxTimeout: time.Duration(30) * time.Second,
lazyLimit: true,
maxSize: 100,
}
redisObj.redisCli = &redis.Pool{
MaxIdle: redisObj.maxIdle,
MaxActive: redisObj.maxActive,
IdleTimeout: redisObj.maxIdleTimeout,
Wait: true,
Dial: func() (redis.Conn, error) {
con, err := redis.Dial(
"tcp",
"127.0.0.1:6379", // address
redis.DialPassword(""),
redis.DialDatabase(int(0)),
redis.DialConnectTimeout(redisObj.maxTimeout),
redis.DialReadTimeout(redisObj.maxTimeout),
redis.DialWriteTimeout(redisObj.maxTimeout),
)
if err != nil {
return nil, err
}
return con, nil
},
}
return redisObj, nil
}
controller中存储、获取:
func main() {
//放入验证码及关联手机号
redisCli,err := redis.ProducetRedis()
if err != nil {
fmt.Println("redis链接错误",err.Error())
return
}
redisCli.Put("18888888888","8888",3600)
//根据key取出code
code,_ := redisCli.GetNoWait("18888888888")
fmt.Println(code)
}
(二) 整合jwt
用到 "github.com/dgrijalva/jwt-go" 以及 路由mux "github.com/gorilla/mux"
登录生成token的方法:
func GenerateToken(user *model.User) (string, error) {
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"account": user.Account,
"exp" : time.Now().Add(time.Hour * 2).Unix(),
})
return token.SignedString([]byte("secret"))
}
在登录接口中调用生成,并将token返回给前端,需要鉴权的接口每次调用需要在header中传入token。
router.go
package router
import (
"github.com/gorilla/mux"
"myfirstgoproject/api"
"net/http"
)
type Route struct {
Method string
Pattern string
Handler http.HandlerFunc
Middleware mux.MiddlewareFunc
}
var routes []Route
func init() {
register("POST", "/user/edit_pwd", api.EditPwd, auth.TokenMiddleware)
register("POST", "/user/send_msg", api.SendMsg, nil)
register("POST", "/user/login", api.Login, nil)
register("POST", "/user/register", api.Register, nil)
}
func register(method, pattern string, handler http.HandlerFunc, middleware mux.MiddlewareFunc) {
routes = append(routes, Route{method, pattern, handler, middleware})
}
func NewRouter() *mux.Router {
router := mux.NewRouter()
for _, route := range routes {
r := router.Methods(route.Method).
Path(route.Pattern)
if route.Middleware != nil {
r.Handler(route.Middleware(route.Handler))
} else {
r.Handler(route.Handler)
}
}
return router
}
auth.go 实现身份验证鉴权的中间件方法
package auth
import (
"fmt"
"github.com/dgrijalva/jwt-go"
"myfirstgoproject/util"
"net/http"
)
func TokenMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
tokenStr := r.Header.Get("accessToken")
if tokenStr == "" {
fmt.Println("error authorized nil")
} else {
token, _ := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("not authorization")
}
return []byte("secret"), nil
})
if !token.Valid {
fmt.Println("error authorized nil")
} else {
next.ServeHTTP(w, r)
}
}
})
}
对需要身份验证的路由添加中间件auth.TokenMiddleware
当访问edit_pwd时如果header中没有accessToken参数,将不能访问。