Skip to content

Commit

Permalink
feat: 增加登录后回跳来源地址
Browse files Browse the repository at this point in the history
前端
- 管理后台未登录跳登录页增加携带回跳地址

后端
- 登录接口增加二次回跳参数,支持登录后回调原地址
  • Loading branch information
jorben committed Jul 10, 2024
1 parent 973d788 commit 585211c
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 19 deletions.
5 changes: 2 additions & 3 deletions provider/auth/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,11 @@ func NewGithubOAuth(c config.OAuthProvider) *GithubOAuth {
return &GithubOAuth{cfg: c}
}

func (g *GithubOAuth) GetLoginUrl(ctx *gin.Context) (string, error) {
cbUrl := fmt.Sprintf("%s&state=%s", g.cfg.CallbackUri, g.cfg.State)
func (g *GithubOAuth) GetLoginUrl(ctx *gin.Context, redirect string) (string, error) {
return fmt.Sprintf(
"https://github.com/login/oauth/authorize?client_id=%s&redirect_uri=%s",
g.cfg.ClientId,
url.QueryEscape(cbUrl),
url.QueryEscape(fmt.Sprintf("%s&state=%s&redirect_uri=%s", g.cfg.CallbackUri, g.cfg.State, url.QueryEscape(redirect))),
), nil
}

Expand Down
3 changes: 2 additions & 1 deletion provider/auth/google.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ func NewGoogleOAuth(c config.OAuthProvider) *GoogleOAuth {
}
}

func (g *GoogleOAuth) GetLoginUrl(ctx *gin.Context) (string, error) {
func (g *GoogleOAuth) GetLoginUrl(ctx *gin.Context, redirect string) (string, error) {
// 暂未找到 google auth 携带二次回调的方法,注入callback中会无法匹配
return g.googleOAuth2Config.AuthCodeURL(g.cfg.State), nil
}

Expand Down
4 changes: 2 additions & 2 deletions provider/auth/wechat.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ func NewWechatOAuth(c config.OAuthProvider) *WechatOAuth {
}

// GetLoginUrl 获取登录URL
func (g *WechatOAuth) GetLoginUrl(ctx *gin.Context) (string, error) {
func (g *WechatOAuth) GetLoginUrl(ctx *gin.Context, redirect string) (string, error) {

return fmt.Sprintf(
"https://open.weixin.qq.com/connect/qrconnect?appid=%s&scope=snsapi_login&redirect_uri=%s&state=%s",
g.cfg.ClientId,
url.QueryEscape(g.cfg.CallbackUri),
url.QueryEscape(fmt.Sprintf("%s&redirect_uri=%s", g.cfg.CallbackUri, url.QueryEscape(redirect))),
g.cfg.State,
), nil
}
Expand Down
10 changes: 8 additions & 2 deletions router/api/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (

// AuthProvider 第三方登录渠道接口
type AuthProvider interface {
GetLoginUrl(ctx *gin.Context) (string, error)
GetLoginUrl(ctx *gin.Context, redirect string) (string, error)
GetUserinfo(ctx *gin.Context) (*model.UserSocialInfo, error)
}

Expand All @@ -31,6 +31,12 @@ func AuthLogin(ctx *gin.Context) {
providerConfig = config.GetAuthProviderConfig(provider)
}

// 获取登录成功后的回调地址
redirect := ctx.Query("redirect_uri")
if len(redirect) == 0 {
redirect = "/"
}

// 创建provider实例
switch provider {
case auth.ProviderGithub:
Expand All @@ -45,7 +51,7 @@ func AuthLogin(ctx *gin.Context) {
}

// 执行provider登录构造
url, err := oAuthClient.GetLoginUrl(ctx)
url, err := oAuthClient.GetLoginUrl(ctx, redirect)
if err != nil {
log.Errorf(ctx, "Get %s login url failed, err: %s", provider, err.Error())
c.CJSON(errs.ErrAuthLoginUrl)
Expand Down
41 changes: 34 additions & 7 deletions web/src/pages/Login.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,26 @@ const Login = () => {
const location = useLocation();
const navigate = useNavigate();
const [wxLoginUrl, setWxLoginUrl] = useState("");
const searchParams = new URLSearchParams(location.search);
const searchParams = React.useMemo(() => {
return new URLSearchParams(location.search);
}, [location]);
const isCallback = searchParams.get("callback");

const [messageApi, contextHolder] = message.useMessage();
const getRedirect = React.useCallback(() => {
try {
const r = searchParams.get("redirect_uri") || "/";
// 尝试将输入解析为URL对象
const parsedUrl = new URL(r, "http://dummybase");
// 获取路径和查询字符串
const pathAndQuery = parsedUrl.pathname + parsedUrl.search;
// 如果路径和查询字符串是根路径(即"/"),则返回空字符串
return pathAndQuery;
} catch (e) {
// 如果输入不是有效的URL(例如相对路径),直接返回输入
return "/";
}
}, [searchParams]);

useEffect(() => {
if (isCallback) {
Expand All @@ -55,7 +71,7 @@ const Login = () => {
);
// 跳转页面
// TODO: 支持跳转回登录来源页面,并做同源校验
navigate("/admin");
navigate(getRedirect());
} else {
messageApi.error(response.data?.message);
}
Expand All @@ -69,7 +85,10 @@ const Login = () => {
} else {
// 登录场景,获取微信地址
const getWxLoginUrl = async () => {
ApiClient.get("/auth/login?type=wechat&url=1")
ApiClient.get(
"/auth/login?type=wechat&url=1&redirect_uri=" +
encodeURIComponent(getRedirect())
)
.then((response) => {
if (response.data?.code === 0) {
setWxLoginUrl(response.data?.data);
Expand All @@ -84,7 +103,7 @@ const Login = () => {
};
getWxLoginUrl();
}
}, [messageApi, isCallback, navigate, location]);
}, [messageApi, isCallback, navigate, location, getRedirect]);

return (
<Layout
Expand Down Expand Up @@ -187,15 +206,21 @@ const Login = () => {
<span>其他登录方式:</span>
<Button
shape="round"
href={CONSTANTS.BASEURL_API + "/auth/login?type=qq"}
href={
CONSTANTS.BASEURL_API +
"/auth/login?type=qq&redirect_uri=" +
encodeURIComponent(getRedirect())
}
icon={<QqOutlined />}
>
QQ
</Button>
<Button
shape="round"
href={
CONSTANTS.BASEURL_API + "/auth/login?type=google"
CONSTANTS.BASEURL_API +
"/auth/login?type=google&redirect_uri=" +
encodeURIComponent(getRedirect())
}
icon={<GoogleOutlined />}
>
Expand All @@ -204,7 +229,9 @@ const Login = () => {
<Button
shape="round"
href={
CONSTANTS.BASEURL_API + "/auth/login?type=github"
CONSTANTS.BASEURL_API +
"/auth/login?type=github&redirect_uri=" +
encodeURIComponent(getRedirect())
}
icon={<GithubOutlined />}
>
Expand Down
6 changes: 5 additions & 1 deletion web/src/pages/admin/layout/AdminFrame.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ const AdminFrame = () => {
response.data?.code === CONSTANTS.ERRCODE.ErrAuthUnauthorized
) {
messageApi.error(response.data?.message, () => {
navigate("/login");
navigate(
`/login?redirect_uri=${encodeURIComponent(
window.location.pathname
)}`
);
});
} else {
messageApi.error(response.data?.message);
Expand Down
6 changes: 5 additions & 1 deletion web/src/pages/admin/layout/AdminHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ const AdminHeader = ({ collapsed, setCollapsed }) => {
icon={<LogoutOutlined />}
onClick={() => {
localStorage.removeItem(CONSTANTS.STORAGE_KEY_JWT);
navigate("/login");
navigate(
`/login?redirect_uri=${encodeURIComponent(
window.location.pathname
)}`
);
}}
>
退出登录
Expand Down
4 changes: 3 additions & 1 deletion web/src/pages/admin/user/UserDetail.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ const UserDetail = ({ user }) => {
) {
messageApi.error(response.data?.message, () => {
navigate(
`/login?redirect=${encodeURIComponent(window.location.href)}`
`/login?redirect_uri=${encodeURIComponent(
window.location.pathname
)}`
);
});
} else {
Expand Down
6 changes: 5 additions & 1 deletion web/src/pages/admin/user/UserList.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,11 @@ const UserList = () => {
response.data?.code === CONSTANTS.ERRCODE.ErrAuthUnauthorized
) {
messageApi.error(response.data?.message, () => {
navigate("/login");
navigate(
`/login?redirect_uri=${encodeURIComponent(
window.location.pathname
)}`
);
});
} else {
messageApi.error(response.data?.message);
Expand Down

0 comments on commit 585211c

Please sign in to comment.