fix: fix oauth2 state not checking

This commit is contained in:
JustSong 2023-09-15 00:24:20 +08:00
parent b57a0eca16
commit 39ae8075e4
6 changed files with 57 additions and 18 deletions

View File

@ -79,6 +79,14 @@ func getGitHubUserInfoByCode(code string) (*GitHubUser, error) {
func GitHubOAuth(c *gin.Context) { func GitHubOAuth(c *gin.Context) {
session := sessions.Default(c) session := sessions.Default(c)
state := c.Query("state")
if state == "" || session.Get("oauth_state") == nil || state != session.Get("oauth_state").(string) {
c.JSON(http.StatusForbidden, gin.H{
"success": false,
"message": "state is empty or not same",
})
return
}
username := session.Get("username") username := session.Get("username")
if username != nil { if username != nil {
GitHubBind(c) GitHubBind(c)
@ -205,3 +213,22 @@ func GitHubBind(c *gin.Context) {
}) })
return return
} }
func GenerateOAuthCode(c *gin.Context) {
session := sessions.Default(c)
state := common.GetRandomString(12)
session.Set("oauth_state", state)
err := session.Save()
if err != nil {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
"data": state,
})
}

View File

@ -21,6 +21,7 @@ func SetApiRouter(router *gin.Engine) {
apiRouter.GET("/reset_password", middleware.CriticalRateLimit(), middleware.TurnstileCheck(), controller.SendPasswordResetEmail) apiRouter.GET("/reset_password", middleware.CriticalRateLimit(), middleware.TurnstileCheck(), controller.SendPasswordResetEmail)
apiRouter.POST("/user/reset", middleware.CriticalRateLimit(), controller.ResetPassword) apiRouter.POST("/user/reset", middleware.CriticalRateLimit(), controller.ResetPassword)
apiRouter.GET("/oauth/github", middleware.CriticalRateLimit(), controller.GitHubOAuth) apiRouter.GET("/oauth/github", middleware.CriticalRateLimit(), controller.GitHubOAuth)
apiRouter.GET("/oauth/state", middleware.CriticalRateLimit(), controller.GenerateOAuthCode)
apiRouter.GET("/oauth/wechat", middleware.CriticalRateLimit(), controller.WeChatAuth) apiRouter.GET("/oauth/wechat", middleware.CriticalRateLimit(), controller.WeChatAuth)
apiRouter.GET("/oauth/wechat/bind", middleware.CriticalRateLimit(), middleware.UserAuth(), controller.WeChatBind) apiRouter.GET("/oauth/wechat/bind", middleware.CriticalRateLimit(), middleware.UserAuth(), controller.WeChatBind)
apiRouter.GET("/oauth/email/bind", middleware.CriticalRateLimit(), middleware.UserAuth(), controller.EmailBind) apiRouter.GET("/oauth/email/bind", middleware.CriticalRateLimit(), middleware.UserAuth(), controller.EmailBind)

View File

@ -13,8 +13,8 @@ const GitHubOAuth = () => {
let navigate = useNavigate(); let navigate = useNavigate();
const sendCode = async (code, count) => { const sendCode = async (code, state, count) => {
const res = await API.get(`/api/oauth/github?code=${code}`); const res = await API.get(`/api/oauth/github?code=${code}&state=${state}`);
const { success, message, data } = res.data; const { success, message, data } = res.data;
if (success) { if (success) {
if (message === 'bind') { if (message === 'bind') {
@ -36,13 +36,14 @@ const GitHubOAuth = () => {
count++; count++;
setPrompt(`出现错误,第 ${count} 次重试中...`); setPrompt(`出现错误,第 ${count} 次重试中...`);
await new Promise((resolve) => setTimeout(resolve, count * 2000)); await new Promise((resolve) => setTimeout(resolve, count * 2000));
await sendCode(code, count); await sendCode(code, state, count);
} }
}; };
useEffect(() => { useEffect(() => {
let code = searchParams.get('code'); let code = searchParams.get('code');
sendCode(code, 0).then(); let state = searchParams.get('state');
sendCode(code, state, 0).then();
}, []); }, []);
return ( return (

View File

@ -3,6 +3,7 @@ import { Button, Divider, Form, Grid, Header, Image, Message, Modal, Segment } f
import { Link, useNavigate, useSearchParams } from 'react-router-dom'; import { Link, useNavigate, useSearchParams } from 'react-router-dom';
import { UserContext } from '../context/User'; import { UserContext } from '../context/User';
import { API, getLogo, showError, showSuccess } from '../helpers'; import { API, getLogo, showError, showSuccess } from '../helpers';
import { getOAuthState, onGitHubOAuthClicked } from './utils';
const LoginForm = () => { const LoginForm = () => {
const [inputs, setInputs] = useState({ const [inputs, setInputs] = useState({
@ -31,12 +32,6 @@ const LoginForm = () => {
const [showWeChatLoginModal, setShowWeChatLoginModal] = useState(false); const [showWeChatLoginModal, setShowWeChatLoginModal] = useState(false);
const onGitHubOAuthClicked = () => {
window.open(
`https://github.com/login/oauth/authorize?client_id=${status.github_client_id}&scope=user:email`
);
};
const onWeChatLoginClicked = () => { const onWeChatLoginClicked = () => {
setShowWeChatLoginModal(true); setShowWeChatLoginModal(true);
}; };
@ -131,7 +126,7 @@ const LoginForm = () => {
circular circular
color='black' color='black'
icon='github' icon='github'
onClick={onGitHubOAuthClicked} onClick={()=>onGitHubOAuthClicked(status.github_client_id)}
/> />
) : ( ) : (
<></> <></>

View File

@ -4,6 +4,7 @@ import { Link, useNavigate } from 'react-router-dom';
import { API, copy, showError, showInfo, showNotice, showSuccess } from '../helpers'; import { API, copy, showError, showInfo, showNotice, showSuccess } from '../helpers';
import Turnstile from 'react-turnstile'; import Turnstile from 'react-turnstile';
import { UserContext } from '../context/User'; import { UserContext } from '../context/User';
import { onGitHubOAuthClicked } from './utils';
const PersonalSetting = () => { const PersonalSetting = () => {
const [userState, userDispatch] = useContext(UserContext); const [userState, userDispatch] = useContext(UserContext);
@ -130,12 +131,6 @@ const PersonalSetting = () => {
} }
}; };
const openGitHubOAuth = () => {
window.open(
`https://github.com/login/oauth/authorize?client_id=${status.github_client_id}&scope=user:email`
);
};
const sendVerificationCode = async () => { const sendVerificationCode = async () => {
setDisableButton(true); setDisableButton(true);
if (inputs.email === '') return; if (inputs.email === '') return;
@ -249,7 +244,7 @@ const PersonalSetting = () => {
</Modal> </Modal>
{ {
status.github_oauth && ( status.github_oauth && (
<Button onClick={openGitHubOAuth}>绑定 GitHub 账号</Button> <Button onClick={()=>{onGitHubOAuthClicked(status.github_client_id)}}>绑定 GitHub 账号</Button>
) )
} }
<Button <Button

View File

@ -0,0 +1,20 @@
import { API, showError } from '../helpers';
export async function getOAuthState() {
const res = await API.get('/api/oauth/state');
const { success, message, data } = res.data;
if (success) {
return data;
} else {
showError(message);
return '';
}
}
export async function onGitHubOAuthClicked(github_client_id) {
const state = await getOAuthState();
if (!state) return;
window.open(
`https://github.com/login/oauth/authorize?client_id=${github_client_id}&state=${state}&scope=user:email`
);
}