|
@ -1,42 +1,43 @@ |
|
|
package main |
|
|
package main |
|
|
|
|
|
|
|
|
import ( |
|
|
import ( |
|
|
"crypto/sha1" |
|
|
|
|
|
"encoding/xml" |
|
|
|
|
|
"fmt" |
|
|
"fmt" |
|
|
|
|
|
"html/template" |
|
|
"log" |
|
|
"log" |
|
|
"net/http" |
|
|
"net/http" |
|
|
"sort" |
|
|
|
|
|
"strings" |
|
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"blog.bing89.com/go/wechat/wechat" |
|
|
"github.com/gin-gonic/gin" |
|
|
"github.com/gin-gonic/gin" |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
const ( |
|
|
const ( |
|
|
appID = "wxc39301065b66300c" |
|
|
appID = "wxc39301065b66300c" |
|
|
secret = "7fee3a1cba8c555cf6c4caec4f05844c" |
|
|
secret = "7fee3a1cba8c555cf6c4caec4f05844c" |
|
|
token = "qwertyuiopasdfghjkl" |
|
|
token = "qwertyuiopasdfghjkl" |
|
|
|
|
|
Secret = "0a05cb757a9e4fdc9b1aac4f0406a3df" |
|
|
|
|
|
Appid = "wx2fa7fb238aa6896a" |
|
|
|
|
|
Encodingaeskey = "Lw2YDq9Svzhi5HeTzldcG5ID7rlgsJkQ5tDv8wwa092" |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
//////
|
|
|
type Server struct { |
|
|
type messageEntity struct { |
|
|
w *wechat.Wechat |
|
|
Signature string `form:"signature"` |
|
|
users map[string]*wechat.UserInfo |
|
|
Timestamp string `form:"timestamp"` |
|
|
|
|
|
Nonce string `form:"nonce"` |
|
|
|
|
|
EchoStr string `form:"echostr"` |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (m *messageEntity) CheckSignature(token string) bool { |
|
|
func NewServer() (*Server, error) { |
|
|
item := []string{token, m.Timestamp, m.Nonce} |
|
|
w, err := wechat.NewWechat(Appid, Secret) |
|
|
sort.Strings(item) |
|
|
if err != nil { |
|
|
itemByte := strings.Join(item, "") |
|
|
return nil, err |
|
|
signature := fmt.Sprintf("%x", sha1.Sum([]byte(itemByte))) |
|
|
} |
|
|
return signature == m.Signature |
|
|
s := Server{ |
|
|
|
|
|
w: w, |
|
|
|
|
|
users: make(map[string]*wechat.UserInfo), |
|
|
|
|
|
} |
|
|
|
|
|
return &s, nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func Check(c *gin.Context) { |
|
|
func (s *Server) Check(c *gin.Context) { |
|
|
me := &messageEntity{} |
|
|
me := &wechat.MessageEntity{} |
|
|
me.Signature = c.Query("signature") |
|
|
me.Signature = c.Query("signature") |
|
|
me.Timestamp = c.Query("timestamp") |
|
|
me.Timestamp = c.Query("timestamp") |
|
|
me.Nonce = c.Query("nonce") |
|
|
me.Nonce = c.Query("nonce") |
|
@ -47,43 +48,25 @@ func Check(c *gin.Context) { |
|
|
c.AbortWithError(http.StatusForbidden, fmt.Errorf("token invalid")) |
|
|
c.AbortWithError(http.StatusForbidden, fmt.Errorf("token invalid")) |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
c.Set("echostr", me.EchoStr) |
|
|
c.Next() |
|
|
c.Next() |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
////
|
|
|
////
|
|
|
type foucsData struct { |
|
|
|
|
|
ToUserName string `xml:"ToUserName"` |
|
|
|
|
|
FromUserName string `xml:"FromUserName"` |
|
|
|
|
|
CreateTime int64 `xml:"CreateTime"` |
|
|
|
|
|
MsgType string `xml:"MsgType"` |
|
|
|
|
|
Event string `xml:"Event"` |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
////
|
|
|
func cdata(data string) string { |
|
|
type textMessage struct { |
|
|
|
|
|
ToUserName string `xml:"ToUserName"` |
|
|
|
|
|
FromUserName string `xml:"FromUserName"` |
|
|
|
|
|
CreateTime int64 `xml:"CreateTime"` |
|
|
|
|
|
MsgType string `xml:"MsgType"` |
|
|
|
|
|
Content string `xml:"Content"` |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func cdata(data string)string{ |
|
|
|
|
|
return fmt.Sprintf(`<![CDATA[%s]]>`, data) |
|
|
return fmt.Sprintf(`<![CDATA[%s]]>`, data) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func handleGet(c *gin.Context) { |
|
|
func (s *Server) handleGet(c *gin.Context) { |
|
|
me := &messageEntity{} |
|
|
echoStr := c.GetString("echostr") |
|
|
me.Signature = c.Query("signature") |
|
|
|
|
|
me.Timestamp = c.Query("timestamp") |
|
|
|
|
|
me.Nonce = c.Query("nonce") |
|
|
|
|
|
me.EchoStr = c.Query("echostr") |
|
|
|
|
|
log.Println("signature:", me.Signature, "timestamp:", me.Timestamp, "noce:", me.Nonce, "echostr:", me.EchoStr) |
|
|
|
|
|
log.Println("token is ok") |
|
|
log.Println("token is ok") |
|
|
c.String(http.StatusOK, me.EchoStr) |
|
|
c.String(http.StatusOK, echoStr) |
|
|
} |
|
|
} |
|
|
func handlePost(c *gin.Context) { |
|
|
|
|
|
data := foucsData{} |
|
|
//关注
|
|
|
|
|
|
func (s *Server) handlePost(c *gin.Context) { |
|
|
|
|
|
data := wechat.FoucsRequest{} |
|
|
err := c.BindXML(&data) |
|
|
err := c.BindXML(&data) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
log.Println(err) |
|
|
log.Println(err) |
|
@ -91,22 +74,21 @@ func handlePost(c *gin.Context) { |
|
|
log.Println("data: ", data) |
|
|
log.Println("data: ", data) |
|
|
openID := c.Query("openid") |
|
|
openID := c.Query("openid") |
|
|
log.Println("openid is ", openID) |
|
|
log.Println("openid is ", openID) |
|
|
t := textMessage{ |
|
|
res, err := s.w.SendText(data.FromUserName, "welcome to xk.design.") |
|
|
ToUserName: cdata(data.FromUserName), |
|
|
log.Printf("res: %s\nerr:%v", string(res), err) |
|
|
FromUserName: cdata(data.ToUserName), |
|
|
ui, err := s.w.GetUserInfo(data.FromUserName) |
|
|
CreateTime: time.Now().Unix(), |
|
|
if err == nil { |
|
|
MsgType: cdata("text"), |
|
|
s.users[ui.OpenID] = ui |
|
|
Content: cdata("你关注了我!"), |
|
|
ui.Show() |
|
|
} |
|
|
} |
|
|
d, err := xml.Marshal(&t) |
|
|
|
|
|
if err != nil { |
|
|
if err != nil { |
|
|
log.Println("marshar message faild", err) |
|
|
log.Printf("get ui err:%v", err) |
|
|
} |
|
|
} |
|
|
c.String(http.StatusOK, string(d)) |
|
|
c.String(http.StatusOK, "success") |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func handlePut(c *gin.Context) { |
|
|
func (s *Server) handlePut(c *gin.Context) { |
|
|
data :=foucsData{} |
|
|
data := wechat.FoucsRequest{} |
|
|
err := c.BindXML(&data) |
|
|
err := c.BindXML(&data) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
log.Println(err) |
|
|
log.Println(err) |
|
@ -115,8 +97,8 @@ func handlePut(c *gin.Context) { |
|
|
c.String(http.StatusOK, "success") |
|
|
c.String(http.StatusOK, "success") |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func handleDelete(c *gin.Context) { |
|
|
func (s *Server) handleDelete(c *gin.Context) { |
|
|
data := foucsData{} |
|
|
data := wechat.FoucsRequest{} |
|
|
err := c.BindXML(&data) |
|
|
err := c.BindXML(&data) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
log.Println(err) |
|
|
log.Println(err) |
|
@ -125,13 +107,62 @@ func handleDelete(c *gin.Context) { |
|
|
c.String(http.StatusOK, "success") |
|
|
c.String(http.StatusOK, "success") |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//@router /auth/login
|
|
|
|
|
|
func (s *Server) login(c *gin.Context) { |
|
|
|
|
|
code := c.Query("code") |
|
|
|
|
|
if code == "" { |
|
|
|
|
|
c.AbortWithError(http.StatusBadRequest, fmt.Errorf("no code")) |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
ticket, err := s.w.CreateQRCode() |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
|
func main() { |
|
|
} |
|
|
|
|
|
log.Printf("ticket: %s\nurl: %s\n err:%v\n", ticket.Ticket, ticket.URL, ticket.ExpireSeconds) |
|
|
|
|
|
log.Println("==========> code is: ", code) |
|
|
|
|
|
c.HTML(http.StatusOK, "next", gin.H{"next": template.HTML(ticket.URL)}) |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (s *Server) Template(name string) *template.Template { |
|
|
|
|
|
tmpl := template.New(name) |
|
|
|
|
|
tmpl.Parse(s.html()) |
|
|
|
|
|
return tmpl |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (s *Server) html() string { |
|
|
|
|
|
return `<html> |
|
|
|
|
|
<head> |
|
|
|
|
|
<meta charset="utf-8"> |
|
|
|
|
|
<title>Login</title> |
|
|
|
|
|
</head><body></body><script>window.location.href='{{.next}}?#wechat_redirect';</script></html>` |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (s *Server) Run(addr string) error { |
|
|
engine := gin.Default() |
|
|
engine := gin.Default() |
|
|
engine.Use(Check) |
|
|
engine.SetHTMLTemplate(s.Template("next")) |
|
|
engine.GET("/api/wechat/signature", handleGet) |
|
|
apiGroup := engine.Group("/api/wechat") |
|
|
engine.POST("/api/wechat/signature", handlePost) |
|
|
apiGroup.Use(s.Check) |
|
|
engine.PUT("/api/wechat/signature", handlePut) |
|
|
apiGroup.GET("/signature", s.handleGet) |
|
|
engine.DELETE("/api/wechat/signature", handleDelete) |
|
|
apiGroup.POST("/signature", s.handlePost) |
|
|
engine.Run("0.0.0.0:15043") |
|
|
apiGroup.PUT("/signature", s.handlePut) |
|
|
|
|
|
apiGroup.DELETE("/signature", s.handleDelete) |
|
|
|
|
|
authGroup := engine.Group("/auth") |
|
|
|
|
|
authGroup.GET("/login", s.login) |
|
|
|
|
|
|
|
|
|
|
|
return engine.Run(addr) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxc39301065b66300c&redirect_uri=http://106.55.59.210:15043/auth/login&response_type=code&scope=snsapi_userinfo#wechat_redirect
|
|
|
|
|
|
// https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxc39301065b66300c&redirect_uri=http%3A%2F%2F106.55.59.210%3A15043%2Fauth%2Flogin&response_type=code&scope=snsapi_userinfo&connect_redirect=1#wechat_redirect
|
|
|
|
|
|
func main() { |
|
|
|
|
|
s, err := NewServer() |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
log.Fatal(err) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
err = s.Run("0.0.0.0:15043") |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
log.Fatal(err) |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|