<p>我为Ory Kratos设置流程创建了自己的用户界面。我遇到的问题是,尽管返回的消息显示我的设置已成功更新,但我的新密码没有反映出来,我也没有成功恢复我的账户。以下是我使用Vue 3渲染UI的代码片段。</p>
<pre class="brush:js;toolbar:false;">// SettingsVue.vue
<template>
<div id="settings">
<HomeTopbar :views="[]" />
<div class="settings-wrapper">
<h1 class="poppins fs_3 fw_6">恢复您的密码</h1>
<OryFlow v-if="settingsFlow"
:flow="settingsFlow"
title="登录"
form-id="settings-form"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
/* ory */
import { injectStrict } from '@/utils';
import { $ory } from '@/plugins/ory';
import { makeHandleGetFlowError } from '@/utils/flows';
/* types */
import type { SelfServiceSettingsFlow } from '@ory/kratos-client';
/* composables */
import { useRoute, useRouter } from 'vue-router';
/* components */
import OryFlow from '@/components/flows/OryFlow.vue';
import HomeTopbar from '@/components/ui/HomeTopbar.vue';
const ory = injectStrict($ory);
const route = useRoute();
const router = useRouter();
const settingsFlow = ref<SelfServiceSettingsFlow | undefined>();
const handleGetFlowError = makeHandleGetFlowError(router);
// check if we have a flow param
const { flow } = route.query;
const initializeSelfServiceSettingsFlowForBrowsers = () =>
ory
.initializeSelfServiceSettingsFlowForBrowsers()
.then((response) => {
settingsFlow.value = response.data;
router.replace({
query: {
flow: response.data.id,
},
});
})
.catch(handleGetFlowError);
if (typeof flow !== 'string') {
// if there's no flow in our route,
// we need to initialize our login flow
initializeSelfServiceSettingsFlowForBrowsers();
} else {
ory
.getSelfServiceSettingsFlow(flow)
.then((response) => {
settingsFlow.value = response.data;
})
.catch(handleGetFlowError);
}
</script>
<style scoped lang="scss">
#settings {
width: 100%;
height: 100%;
.settings-wrapper {
margin: var(--space-5) auto 0 auto;
padding: 0 var(--space-3);
margin-top: var(--space-4);
width: 300px;
}
}
</style>
</pre>
<pre class="brush:js;toolbar:false;">#OryFlow.vue
<template>
<div class="ory-flow">
<form :id="formId" :action="flow.ui.action" :method="flow.ui.method">
<OryUiNode v-for="node in flow.ui.nodes"
:key="getNodeId(node)"
:id="getNodeId(node)"
:node="node"
class="ui-node"
/>
</form>
<div class="messages" v-if="flow.ui.messages">
<OryUiMessage v-for="message in flow.ui.messages" :message="message" />
</div>
</div>
</template>
<script setup lang="ts">
import type {
SelfServiceLoginFlow,
SelfServiceRegistrationFlow,
SelfServiceRecoveryFlow,
SelfServiceSettingsFlow,
SelfServiceVerificationFlow,
} from '@ory/kratos-client';
import OryUiNode from './OryUiNode.vue';
import OryUiMessage from './OryUiMessage.vue';
import { getNodeId } from '@ory/integrations/ui';
defineProps<{
flow:
| SelfServiceLoginFlow
| SelfServiceRegistrationFlow
| SelfServiceRecoveryFlow
| SelfServiceSettingsFlow
| SelfServiceVerificationFlow;
formId?: string;
}>();
</script>
<style scoped lang="scss">
.ui-node + .ui-node {
margin-top: var(--space-2);
}
.message {
margin-top: var(--space-2);
}
</style>
</pre>
所以解决这个问题实际上非常直接和明显,我在回顾Ory团队创建和维护的React自助服务UI的源代码后,这一点变得明显。
如果你将所有UI节点组一起提交到同一个表单中,它只会在
default组和另一个组上执行。在我的情况下,在成功处理profile组后,它忽略了password组。我遵循的解决方案基本上与我在前一段提到的存储库中提供的解决方案相同。实现一个过滤机制,允许您使用两个单独的表单,从而在提交表单时分离这些值。请记住,您必须始终提交default组,因为它包括您的CSRF令牌。这是解决我的问题的更新代码:
首先,添加对
:only属性的支持,用于过滤节点:// OryFlow.vue现在支持通过'only'属性进行过滤 <template> <div class="ory-flow"> <form :id="formId" :action="flow.ui.action" :method="flow.ui.method" > <OryUiNode v-for="node in nodes" :id="getNodeId(node)" :key="getNodeId(node)" :node="node" class="ui-node" /> </form> <div v-if="flow.ui.messages" class="messages" > <OryUiMessage v-for="message in flow.ui.messages" :key="message.id" :message="message" /> </div> </div> </template> <script setup lang="ts"> import type { SelfServiceLoginFlow, SelfServiceRegistrationFlow, SelfServiceRecoveryFlow, SelfServiceSettingsFlow, SelfServiceVerificationFlow, } from '@ory/kratos-client'; import OryUiNode from './OryUiNode.vue'; import OryUiMessage from './OryUiMessage.vue'; import { getNodeId } from '@ory/integrations/ui'; import { computed, toRefs } from 'vue'; const props = defineProps<{ flow: | SelfServiceLoginFlow | SelfServiceRegistrationFlow | SelfServiceRecoveryFlow | SelfServiceSettingsFlow | SelfServiceVerificationFlow; formId?: string; only?: string | string[]; }>(); const { flow, only } = toRefs(props); const nodes = computed(() => { if (!only?.value) { return flow.value.ui.nodes; } const onlyArr: string[] = Array.isArray(only.value) ? only.value : [only.value]; const onlyMap = onlyArr.reduce((acc, curr: string) => { acc[curr] = true; return acc; }, {} as Record<string, boolean>); return flow.value.ui.nodes.filter((node) => onlyMap[node.group]); }); </script>接下来,在一个表单中利用这个新的属性来仅过滤节点组
password和default。您可以使用相同的方法在另一个表单中过滤profile和default。// SettingsView.vue <template> <div id="settings"> <HomeTopbar :views="[]" /> <div class="settings-wrapper"> <h1 class="poppins fs_3 fw_6">Recover your password</h1> <!-- 在这里添加only属性 --> <OryFlow v-if="settingsFlow" :flow="settingsFlow" title="Login" form-id="settings-form" :only="[ 'password', 'default' ]" /> </div> </div> </template>