Skip to content

Commit

Permalink
improve: 不自动销毁 u2f token,5mins 内记住校验令牌
Browse files Browse the repository at this point in the history
  • Loading branch information
Mmx233 committed Oct 30, 2023
1 parent 77f2e78 commit 900cafd
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 40 deletions.
3 changes: 1 addition & 2 deletions internal/pkg/jwt/jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,13 @@ func GenerateU2fToken(uid uint, ip string) (string, *U2fToken, error) {
return token, tokenClaims, err
}

// ParseU2fToken 自动销毁
func ParseU2fToken(token, ip string) (bool, error) {
claims, valid, err := ParseToken("U2F", token, &U2fToken{})
if err != nil || !valid || claims.IP != ip {
return false, err
}

err = redis.NewU2F(claims.UID).NewStorePoint(claims.ID).GetAndDestroy(context.Background(), claims.IssuedAt.Time, nil)
err = redis.NewU2F(claims.UID).NewStorePoint(claims.ID).Get(context.Background(), claims.IssuedAt.Time, nil)
if err != nil {
if err == redis.Nil {
err = nil
Expand Down
2 changes: 1 addition & 1 deletion internal/pkg/tokenStore/tokenStore.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func (a Point) GetAndDestroy(ctx context.Context, iat time.Time, claims interfac
}

func (a Point) Get(ctx context.Context, iat time.Time, claims interface{}) error {
value, err := a.s.client.GetDel(ctx, a.key).Bytes()
value, err := a.s.client.Get(ctx, a.key).Bytes()
if err != nil {
return err
}
Expand Down
110 changes: 73 additions & 37 deletions web/src/components/user/U2fDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
Typography,
Stack,
TextField,
Alert,
AlertTitle,
} from "@mui/material";
import { LoadingButton } from "@mui/lab";
import {
Expand Down Expand Up @@ -43,6 +45,9 @@ const U2fDialog: FC = () => {
}),
shallow
);
const u2fToken = useU2fDialog((state) => state.u2f);

const [tokenAvailable, setTokenAvailable] = useState(false);

const [tabValue, setTabValue] = useState<User.U2F.Methods>("");
const [isLoading, setIsLoading] = useState(false);
Expand All @@ -57,13 +62,29 @@ const U2fDialog: FC = () => {

const [mfaCode, setMfaCode] = useState("");

const isTokenAvailable = () => {
return !!u2fToken && u2fToken.valid_before > Date.now() / 1000;
};
useInterval(
() => {
if (!isTokenAvailable()) setTokenAvailable(false);
},
tokenAvailable ? 1000 : null
);

const onCancel = () => {
const states = useU2fDialog.getState();
states.closeDialog();
if (states.reject) states.reject("user canceled");
};

const onSubmit = async (method: string = tabValue) => {
if (tokenAvailable) {
const states = useU2fDialog.getState();
if (states.resolve) states.resolve(u2fToken!);
states.closeDialog();
return;
}
let data: any;
switch (method) {
case "phone":
Expand Down Expand Up @@ -147,7 +168,8 @@ const U2fDialog: FC = () => {
if (open) {
setMfaCode("");
setSmsCode("");
if (tabValue === "passkey") onSubmit();
if (isTokenAvailable()) setTokenAvailable(true);
else if (tabValue === "passkey") onSubmit();
}
}, [open]);
useEffect(() => {
Expand All @@ -163,6 +185,9 @@ const U2fDialog: FC = () => {
case "phone":
return (
<Stack alignItems={"center"}>
<Typography mb={2.5}>
每天上限五条,出现异常情况请过会儿再试
</Typography>
<Stack flexDirection={"row"} width={"100%"} maxWidth={"21rem"}>
<TextField
variant={"outlined"}
Expand Down Expand Up @@ -208,18 +233,18 @@ const U2fDialog: FC = () => {
);
case "passkey":
return (
<Stack alignItems={"center"}>
<SensorOccupiedOutlined
sx={{
fontSize: "6rem",
mt: 2,
mb: 4,
}}
/>
<Button variant={"outlined"} onClick={() => onSubmit()}>
重试
</Button>
</Stack>
<Stack alignItems={"center"}>
<SensorOccupiedOutlined
sx={{
fontSize: "6rem",
mt: 2,
mb: 4,
}}
/>
<Button variant={"outlined"} onClick={() => onSubmit()}>
重试
</Button>
</Stack>
);
default:
return (
Expand All @@ -235,31 +260,42 @@ const U2fDialog: FC = () => {
<Dialog fullWidth open={open} onClose={onCancel}>
<DialogTitle>U2F 身份校验</DialogTitle>
<DialogContent>
<DialogContentText>
{tip ? tip : "你正在进行敏感操作,需要额外的身份校验"}
</DialogContentText>
{!tip && tokenAvailable ? undefined : (
<DialogContentText>
{tip ? tip : "你正在进行敏感操作,需要额外的身份校验"}
</DialogContentText>
)}

<Tabs
value={tabValue}
onChange={(e, value: string) => {
setTabValue(value as User.U2F.Methods);
if (value === "passkey") return onSubmit("passkey");
}}
variant="fullWidth"
sx={{
mt: 2,
mb: 3,
}}
>
<Tab label={"短信"} value={"phone"} disabled={!u2fStatus.phone} />
<Tab label={"MFA"} value={"mfa"} disabled={!u2fStatus.mfa} />
<Tab
label={"通行密钥"}
value={"passkey"}
disabled={!u2fStatus.passkey}
/>
</Tabs>
{renderTabPanel()}
{tokenAvailable ? (
<Alert severity="success">
<AlertTitle>已认证</AlertTitle>
最近 5 分钟已通过验证,无需再次校验。你可以通过刷新提前移除校验状态
</Alert>
) : (
<>
<Tabs
value={tabValue}
onChange={(e, value: string) => {
setTabValue(value as User.U2F.Methods);
if (value === "passkey") return onSubmit("passkey");
}}
variant="fullWidth"
sx={{
mt: 2,
mb: 3,
}}
>
<Tab label={"短信"} value={"phone"} disabled={!u2fStatus.phone} />
<Tab label={"MFA"} value={"mfa"} disabled={!u2fStatus.mfa} />
<Tab
label={"通行密钥"}
value={"passkey"}
disabled={!u2fStatus.passkey}
/>
</Tabs>
{renderTabPanel()}
</>
)}
</DialogContent>
<DialogActions>
<Button onClick={onCancel}>取消</Button>
Expand Down

0 comments on commit 900cafd

Please sign in to comment.