golang(beego)验证码控制器

前端之家收集整理的这篇文章主要介绍了golang(beego)验证码控制器前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

核心代码是封装的别人的

代码如下:

/**
 * 用法
 *1)注册一下路由
 *  beego.Router("/yzm",&controllers.YzmController{},"Get:GetYzm")             //验证码控制器
 *	beego.Router("/yzm/judgeyzm","Post:JudgeYzm") //验证码ajax验证
 *
 * 2)用法
 *  <img src="/yzm" onclick="this.src='/yzm?'+Math.random()" >
 */

package controllers

import (
	crand "crypto/rand"
	// "fmt"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/session"
	"image"
	"image/color"
	"image/png"
	"io"
	"math/rand"
	"net/http"
	"strconv"
	"time"
)

var globalSessions *session.Manager

func init() {
	globalSessions,_ = session.NewManager("memory",`{"cookieName":"gosessionid","enableSetCookie,omitempty": true,"gclifetime":3600,"maxLifetime": 3600,"secure": false,"sessionIDHashFunc": "sha1","sessionIDHashKey": "","cookieLifeTime": 3600,"providerConfig": ""}`)
	go globalSessions.GC()
}

type YzmController struct {
	beego.Controller
}

/**
 * 获取验证码
 */
func (this *YzmController) GetYzm() {
	pic(this.Ctx.ResponseWriter,this.Ctx.Request)
}

/**
 * ajax判断验证码
 */
func (this *YzmController) JudgeYzm() {
	p := this.GetString("param")
	rs := "对不起,输入" + p + "为错误!"
	sess := globalSessions.SessionStart(this.Ctx.ResponseWriter,this.Ctx.Request)
	if sess.Get("yzm") == p {
		rs = "y" //返回y表示正确
	}
	this.Ctx.WriteString(rs)
}

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

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

var font = [][]byte{
	{ // 0
		0,1,},{ // 1
		0,{ // 2
		0,{ // 3
		1,{ // 4
		1,{ // 5
		1,{ // 6
		0,{ // 7
		1,{ // 8
		0,{ // 9
		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)),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,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),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,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,y-yy)
		img.drawHorizLine(color,x-yy,x+yy,y+xx)
		img.drawHorizLine(color,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,r)
	}
}

func (img *Image) drawDigit(digit []byte,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.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,z uint8) (o uint8) {
	o = x
	if y < o {
		o = y
	}
	if z < o {
		o = z
	}
	return
}

func max3(x,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 := ""
	d = []byte(s)
	for v := range d {
		d[v] %= 10
		ss += strconv.FormatInt(int64(d[v]),32)
	}
	w.Header().Set("Content-Type","image/png")
	sess := globalSessions.SessionStart(w,req)
	defer sess.SessionRelease(w)
	sess.Delete("yzm")
	sess.Set("yzm",ss)
	//fmt.Println("-----------------------------------yzm:",sess.Get("yzm"))
	NewImage(d,100,40).WriteTo(w)
}

func index(w http.ResponseWriter,req *http.Request) {
	str := "<Meta charset=\"utf-8\"><h3>golang 图片验证码例子</h3><img border=\"1\" src=\"/pic\" alt=\"图片验证码\" onclick=\"this.src='/pic'\" />"
	w.Header().Set("Content-Type","text/html")
	w.Write([]byte(str))
}

猜你在找的Go相关文章