无法成功更改密码的Ory Kratos设置流程
P粉776412597
P粉776412597 2023-08-31 18:45:58
[Vue.js讨论组]

我为Ory Kratos设置流程创建了自己的用户界面。我遇到的问题是,尽管返回的消息显示我的设置已成功更新,但我的新密码没有反映出来,我也没有成功恢复我的账户。以下是我使用Vue 3渲染UI的代码片段。

// 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>

#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>
P粉776412597
P粉776412597

全部回复(1)
P粉029327711

所以解决这个问题实际上非常直接和明显,我在回顾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>

接下来,在一个表单中利用这个新的属性来仅过滤节点组passworddefault。您可以使用相同的方法在另一个表单中过滤profiledefault

// 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>
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号