-
Notifications
You must be signed in to change notification settings - Fork 28
/
wechat_callback.go
135 lines (115 loc) · 3.75 KB
/
wechat_callback.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package webapp
import (
"net/http"
"github.com/authgear/authgear-server/pkg/api"
"github.com/authgear/authgear-server/pkg/auth/handler/webapp/viewmodels"
"github.com/authgear/authgear-server/pkg/auth/webapp"
"github.com/authgear/authgear-server/pkg/util/httproute"
)
const WechatActionCallback = "callback"
type JSONResponseWriter interface {
WriteResponse(rw http.ResponseWriter, resp *api.Response)
}
func ConfigureWechatCallbackRoute(route httproute.Route) httproute.Route {
return route.
WithMethods("OPTIONS", "POST", "GET").
WithPathPattern("/sso/wechat/callback")
}
// WechatCallbackHandler receives WeChat authorization result (code or error)
// and set it into the web session.
// Refreshing original auth ui WeChat auth page (/sso/wechat/auth/:alias) will
// get and consume the result from the web session.
//
// In web, user will use their WeChat app to scan the qr code in auth ui WeChat
// auth page, then they will complete authorization in their WeChat app and
// redirect to this endpoint through WeChat. This endpoint will set the result
// in web session and instruct user go back to the original auth ui. The
// original auth ui will refresh and proceed.
//
// In native app, the app will receive delegate function call when user click
// login in with WeChat. Developer needs to implement and obtain WeChat
// authorization code through native WeChat SDK. After obtaining the code,
// developer needs to call this endpoint with code through Authgear SDK. At this
// moment, user can click the proceed button in auth ui WeChat auth page to
// continue.
type WechatCallbackHandler struct {
ControllerFactory ControllerFactory
BaseViewModel *viewmodels.BaseViewModeler
JSON JSONResponseWriter
}
func (h *WechatCallbackHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctrl, err := h.ControllerFactory.New(r, w)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
defer ctrl.Serve()
state := r.Form.Get("state")
code := r.Form.Get("code")
error_ := r.Form.Get("error")
errorDescription := r.Form.Get("error_description")
updateWebSession := func() error {
if authflowOAuthState, err := webapp.DecodeAuthflowOAuthState(state); err == nil {
session, err := ctrl.GetSession(authflowOAuthState.WebSessionID)
if err != nil {
return err
}
screen, ok := session.Authflow.AllScreens[authflowOAuthState.XStep]
if !ok {
return webapp.WebUIInvalidSession.New("x_step does not reference a valid screen")
}
screen.WechatCallbackData = &webapp.AuthflowWechatCallbackData{
State: state,
Code: code,
Error: error_,
ErrorDescription: errorDescription,
}
err = ctrl.UpdateSession(session)
if err != nil {
return err
}
return nil
}
// interaction
webSessionID := state
session, err := ctrl.GetSession(webSessionID)
if err != nil {
return err
}
step := session.CurrentStep()
step.FormData["x_action"] = WechatActionCallback
step.FormData["x_code"] = code
step.FormData["x_error"] = error_
step.FormData["x_error_description"] = errorDescription
session.Steps[len(session.Steps)-1] = step
err = ctrl.UpdateSession(session)
if err != nil {
return err
}
return nil
}
handler := func() error {
err := updateWebSession()
// serve api
baseViewModel := h.BaseViewModel.ViewModel(r, w)
if baseViewModel.IsNativePlatform {
if err == nil {
h.JSON.WriteResponse(w, &api.Response{Result: "OK"})
} else {
h.JSON.WriteResponse(w, &api.Response{Error: err})
}
return nil
}
// serve webapp page
if err != nil {
return err
}
result := &webapp.Result{
RedirectURI: "/errors/return",
}
result.WriteResponse(w, r)
return nil
}
ctrl.Get(handler)
ctrl.PostAction("", handler)
}