核心代码是封装的别人的
代码如下:
/** * 用法 *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)) }