海瑞博客

golang 之验证码api

 

知识一:如何返回一个json数据?

    先定义一个结构体ResponseData,2个参数,并返回的是json数据,key就是json后定义的名称

    type ResponseData struct {

       Status  bool         `json:"status"`

       Message string    `json:"message"`

    }

    再定义一个函数,返回结构体的指针。【也就是初始化了一个类,把对象返回一个对象。】

    func NewJsondata() *ResponseData {

       return &ResponseData{}

    }

    使用方法

    result := NewJsondata() // 初始化,返回指针

    result.Status = true  // 赋值,和类赋值相同

    result.Message = "验证成功"

 

知识二:如何定义一个全局变量?

    在函数外定义的都是全局变量

    var RegisterCode  map[string] int64 = make(map[string] int64)

 

知识三:如何获取当前时间戳?

    t := time.Now()

    td := t.Unix()

知识四:map的操作 增加、循环、删除?

    RegisterCode["name"] =“HaiRui”  //增加值

    for k :=range RegisterCode{ //循环

         oldtt := RegisterCode[k] //根据key获取值

         if td - oldtt > 300  { //条件判断

         delete(RegisterCode,k); // 删除值

         }

     }

全部代码【海瑞博客】:

 

package main

import (
	crand "crypto/rand"
	"fmt"
	"image"
	"image/color"
	"image/png"
	"io"
	"math/rand"
	"net/http"
	"strconv"
	"time"
	"encoding/json"
)

const (
	stdWidth  = 100
	stdHeight = 40
	maxSkew   = 2
)

const (
	fontWidth  = 5
	fontHeight = 8
	blackChar  = 1
)

type Validate_Data struct {
	code string
	tt int64
}

type ResponseData struct {
	Status     bool     `json:"status"`
	Message string      `json:"message"`
}

func NewJsondata() *ResponseData {
	return &ResponseData{}
}


var RegisterCode  map[string] int64 = make(map[string] int64)


var font = [][]byte{
	{ // 0
		0, 1, 1, 1, 0,
		1, 0, 0, 0, 1,
		1, 0, 0, 0, 1,
		1, 0, 0, 0, 1,
		1, 0, 0, 0, 1,
		1, 0, 0, 0, 1,
		1, 0, 0, 0, 1,
		0, 1, 1, 1, 0},
	{ // 1
		0, 0, 1, 0, 0,
		0, 1, 1, 0, 0,
		1, 0, 1, 0, 0,
		0, 0, 1, 0, 0,
		0, 0, 1, 0, 0,
		0, 0, 1, 0, 0,
		0, 0, 1, 0, 0,
		1, 1, 1, 1, 1},
	{ // 2
		0, 1, 1, 1, 0,
		1, 0, 0, 0, 1,
		0, 0, 0, 0, 1,
		0, 0, 0, 1, 1,
		0, 1, 1, 0, 0,
		1, 0, 0, 0, 0,
		1, 0, 0, 0, 0,
		1, 1, 1, 1, 1},
	{ // 3
		1, 1, 1, 1, 0,
		0, 0, 0, 0, 1,
		0, 0, 0, 1, 0,
		0, 1, 1, 1, 0,
		0, 0, 0, 1, 0,
		0, 0, 0, 0, 1,
		0, 0, 0, 0, 1,
		1, 1, 1, 1, 0},
	{ // 4
		1, 0, 0, 1, 0,
		1, 0, 0, 1, 0,
		1, 0, 0, 1, 0,
		1, 0, 0, 1, 0,
		1, 1, 1, 1, 1,
		0, 0, 0, 1, 0,
		0, 0, 0, 1, 0,
		0, 0, 0, 1, 0},
	{ // 5
		1, 1, 1, 1, 1,
		1, 0, 0, 0, 0,
		1, 0, 0, 0, 0,
		1, 1, 1, 1, 0,
		0, 0, 0, 0, 1,
		0, 0, 0, 0, 1,
		0, 0, 0, 0, 1,
		1, 1, 1, 1, 0},
	{ // 6
		0, 0, 1, 1, 1,
		0, 1, 0, 0, 0,
		1, 0, 0, 0, 0,
		1, 1, 1, 1, 0,
		1, 0, 0, 0, 1,
		1, 0, 0, 0, 1,
		1, 0, 0, 0, 1,
		0, 1, 1, 1, 0},
	{ // 7
		1, 1, 1, 1, 1,
		0, 0, 0, 0, 1,
		0, 0, 0, 0, 1,
		0, 0, 0, 1, 0,
		0, 0, 1, 0, 0,
		0, 1, 0, 0, 0,
		0, 1, 0, 0, 0,
		0, 1, 0, 0, 0},
	{ // 8
		0, 1, 1, 1, 0,
		1, 0, 0, 0, 1,
		1, 0, 0, 0, 1,
		0, 1, 1, 1, 0,
		1, 0, 0, 0, 1,
		1, 0, 0, 0, 1,
		1, 0, 0, 0, 1,
		0, 1, 1, 1, 0},
	{ // 9
		0, 1, 1, 1, 0,
		1, 0, 0, 0, 1,
		1, 0, 0, 0, 1,
		1, 1, 0, 0, 1,
		0, 1, 1, 1, 1,
		0, 0, 0, 0, 1,
		0, 0, 0, 0, 1,
		1, 1, 1, 1, 0},
}

type Image struct {
	*image.NRGBA
	color   *color.NRGBA
	width   int //a digit width
	height  int //a digit height
	dotsize int
}

func init() {
	rand.Seed(int64(time.Second))

}

func NewImage(digits []byte, width, height int) *Image {
	img := new(Image)
	r := image.Rect(img.width, img.height, stdWidth, stdHeight)
	img.NRGBA = image.NewNRGBA(r)
	img.color = &color.NRGBA{
		uint8(rand.Intn(129)),
		uint8(rand.Intn(129)),
		uint8(rand.Intn(129)),
		0xFF}
	// Draw background (10 random circles of random brightness)
	img.calculateSizes(width, height, len(digits))
	img.fillWithCircles(10, img.dotsize)
	maxx := width - (img.width+img.dotsize)*len(digits) - img.dotsize
	maxy := height - img.height - img.dotsize*2
	x := rnd(img.dotsize*2, maxx)
	y := rnd(img.dotsize*2, maxy)
	// Draw digits.
	for _, n := range digits {
		img.drawDigit(font[n], x, y)
		x += img.width + img.dotsize
	}
	// Draw strike-through line.
	img.strikeThrough()
	return img

}

func (img *Image) WriteTo(w io.Writer) (int64, error) {
	return 0, png.Encode(w, img)

}

func (img *Image) calculateSizes(width, height, ncount int) {
	// Goal: fit all digits inside the image.
	var border int
	if width > height {
		border = height / 5
	} else {
		border = width / 5
	}
	// Convert everything to floats for calculations.
	w := float64(width - border*2)  //268
	h := float64(height - border*2) //48
	// fw takes into account 1-dot spacing between digits.
	fw := float64(fontWidth) + 1 //6
	fh := float64(fontHeight)    //8
	nc := float64(ncount)        //7
	// Calculate the width of a single digit taking into account only the
	// width of the image.
	nw := w / nc //38
	// Calculate the height of a digit from this width.
	nh := nw * fh / fw //51
	// Digit too high?
	if nh > h {
		// Fit digits based on height.
		nh = h //nh = 44
		nw = fw / fh * nh
	}
	// Calculate dot size.
	img.dotsize = int(nh / fh)
	// Save everything, making the actual width smaller by 1 dot to account
	// for spacing between digits.
	img.width = int(nw)
	img.height = int(nh) - img.dotsize

}

func (img *Image) fillWithCircles(n, maxradius int) {
	color := img.color
	maxx := img.Bounds().Max.X
	maxy := img.Bounds().Max.Y
	for i := 0; i < n; i++ {
		setRandomBrightness(color, 255)
		r := rnd(1, maxradius)
		img.drawCircle(color, rnd(r, maxx-r), rnd(r, maxy-r), r)
	}

}

func (img *Image) drawHorizLine(color color.Color, fromX, toX, y int) {
	for x := fromX; x <= toX; x++ {
		img.Set(x, y, color)
	}

}

func (img *Image) drawCircle(color color.Color, x, y, radius int) {
	f := 1 - radius
	dfx := 1
	dfy := -2 * radius
	xx := 0
	yy := radius
	img.Set(x, y+radius, color)
	img.Set(x, y-radius, color)
	img.drawHorizLine(color, x-radius, x+radius, y)
	for xx < yy {
		if f >= 0 {
			yy--
			dfy += 2
			f += dfy
		}
		xx++
		dfx += 2
		f += dfx
		img.drawHorizLine(color, x-xx, x+xx, y+yy)
		img.drawHorizLine(color, x-xx, x+xx, y-yy)
		img.drawHorizLine(color, x-yy, x+yy, y+xx)
		img.drawHorizLine(color, x-yy, x+yy, y-xx)
	}

}

func (img *Image) strikeThrough() {
	r := 0
	maxx := img.Bounds().Max.X
	maxy := img.Bounds().Max.Y
	y := rnd(maxy/3, maxy-maxy/3)
	for x := 0; x < maxx; x += r {
		r = rnd(1, img.dotsize/3)
		y += rnd(-img.dotsize/2, img.dotsize/2)
		if y <= 0 || y >= maxy {
			y = rnd(maxy/3, maxy-maxy/3)
		}
		img.drawCircle(img.color, x, y, r)
	}

}

func (img *Image) drawDigit(digit []byte, x, y int) {
	skf := rand.Float64() * float64(rnd(-maxSkew, maxSkew))
	xs := float64(x)
	minr := img.dotsize / 2               // minumum radius
	maxr := img.dotsize/2 + img.dotsize/4 // maximum radius
	y += rnd(-minr, minr)
	for yy := 0; yy < fontHeight; yy++ {
		for xx := 0; xx < fontWidth; xx++ {
			if digit[yy*fontWidth+xx] != blackChar {
				continue
			}
			// Introduce random variations.
			or := rnd(minr, maxr)
			ox := x + (xx * img.dotsize) + rnd(0, or/2)
			oy := y + (yy * img.dotsize) + rnd(0, or/2)
			img.drawCircle(img.color, ox, oy, or)
		}
		xs += skf
		x = int(xs)
	}

}

func setRandomBrightness(c *color.NRGBA, max uint8) {
	minc := min3(c.R, c.G, c.B)
	maxc := max3(c.R, c.G, c.B)
	if maxc > max {
		return
	}
	n := rand.Intn(int(max-maxc)) - int(minc)
	c.R = uint8(int(c.R) + n)
	c.G = uint8(int(c.G) + n)
	c.B = uint8(int(c.B) + n)

}

func min3(x, y, z uint8) (o uint8) {
	o = x
	if y < o {
		o = y
	}
	if z < o {
		o = z
	}
	return

}

func max3(x, y, z uint8) (o uint8) {
	o = x
	if y > o {
		o = y
	}
	if z > o {
		o = z
	}
	return

}

// rnd returns a random number in range [from, to].

func rnd(from, to int) int {
	//println(to+1-from)
	return rand.Intn(to+1-from) + from

}

const (
	// Standard length of uniuri string to achive ~95 bits of entropy.
	StdLen = 16
	// Length of uniurl string to achive ~119 bits of entropy, closest
	// to what can be losslessly converted to UUIDv4 (122 bits).
	UUIDLen = 20
)

// Standard characters allowed in uniuri string.

var StdChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")

// New returns a new random string of the standard length, consisting of
// standard characters.

func New() string {
	return NewLenChars(StdLen, StdChars)

}

// NewLen returns a new random string of the provided length, consisting of
// standard characters.

func NewLen(length int) string {
	return NewLenChars(length, StdChars)

}

// NewLenChars returns a new random string of the provided length, consisting
// of the provided byte slice of allowed characters (maximum 256).

func NewLenChars(length int, chars []byte) string {
	b := make([]byte, length)
	r := make([]byte, length+(length/4)) // storage for random bytes.
	clen := byte(len(chars))
	maxrb := byte(256 - (256 % len(chars)))
	i := 0
	for {
		if _, err := io.ReadFull(crand.Reader, r); err != nil {
			panic("error reading from random source: " + err.Error())
		}
		for _, c := range r {
			if c >= maxrb {
				// Skip this number to avoid modulo bias.
				continue
			}
			b[i] = chars[c%clen]
			i++
			if i == length {
				return string(b)
			}
		}
	}
	panic("unreachable")

}

func pic(w http.ResponseWriter, req *http.Request) {
	d := make([]byte, 4)
	s := NewLen(4)
	ss := ""
	t := time.Now()
	td := t.Unix()
	// 清除超时验证码
	for k :=range RegisterCode{
		oldtt := RegisterCode[k]
		if td - oldtt > 300  {
			delete(RegisterCode,k);
		}
	}
	d = []byte(s)
	for v := range d {
		d[v] %= 10
		ss += strconv.FormatInt(int64(d[v]), 32)
	}
	RegisterCode[ss] = td

	w.Header().Set("Content-Type", "image/png")
	NewImage(d, 100, 40).WriteTo(w)
	fmt.Println("验证码",ss,RegisterCode)

}

func validate(w http.ResponseWriter, req *http.Request) {
	code := req.FormValue("code") //取值

	result := NewJsondata()
	if code == ""{
		result.Status = false
		result.Message = "请输入验证码"
	}else {
		t := time.Now()
		td := t.Unix()
		// 处理超时的数据
		for k :=range RegisterCode{
			oldtt := RegisterCode[k]
			println(td,oldtt,td - oldtt)
			if td - oldtt > 300  {
				delete(RegisterCode,k);
			}
		}
		_, status := RegisterCode[code]
		if status{
			result.Status = true
			result.Message = "验证成功"
			delete(RegisterCode,code);
		}else {
			result.Status = false
			result.Message = "验证码不正确"
		}
	}
	// 返回数据
	bytes, _ := json.Marshal(result)
	fmt.Fprint(w, string(bytes))
}

func main() {
	http.HandleFunc("/register/pic", pic)
	http.HandleFunc("/register/validate", validate)
	s := &http.Server{
		Addr:           ":8080",
		ReadTimeout:    30 * time.Second,
		WriteTimeout:   30 * time.Second,
		MaxHeaderBytes: 1 << 20}
	s.ListenAndServe()

}

  



posted @ 2017-08-09 09:12  海瑞PYthon  阅读(1627)  评论(0编辑  收藏  举报
海瑞博客