💄 Optimize webpage connections experience
This commit is contained in:
@@ -126,43 +126,6 @@ public class ConnectionController(
|
|||||||
public string? ReturnUrl { get; set; }
|
public string? ReturnUrl { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initiates manual connection to an OAuth provider for the current user
|
|
||||||
/// </summary>
|
|
||||||
[HttpPost("connect")]
|
|
||||||
public async Task<ActionResult<object>> InitiateConnection([FromBody] ConnectProviderRequest request)
|
|
||||||
{
|
|
||||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser)
|
|
||||||
return Unauthorized();
|
|
||||||
|
|
||||||
var oidcService = GetOidcService(request.Provider);
|
|
||||||
if (oidcService == null)
|
|
||||||
return BadRequest($"Provider '{request.Provider}' is not supported");
|
|
||||||
|
|
||||||
var existingConnection = await db.AccountConnections
|
|
||||||
.AnyAsync(c => c.AccountId == currentUser.Id && c.Provider == oidcService.ProviderName);
|
|
||||||
|
|
||||||
if (existingConnection)
|
|
||||||
return BadRequest($"You already have a {request.Provider} connection");
|
|
||||||
|
|
||||||
var state = Guid.NewGuid().ToString("N");
|
|
||||||
var nonce = Guid.NewGuid().ToString("N");
|
|
||||||
var stateValue = $"{currentUser.Id}|{request.Provider}|{nonce}";
|
|
||||||
var finalReturnUrl = !string.IsNullOrEmpty(request.ReturnUrl) ? request.ReturnUrl : "/settings/connections";
|
|
||||||
|
|
||||||
// Store state and return URL in cache
|
|
||||||
await cache.SetAsync($"{StateCachePrefix}{state}", stateValue, StateExpiration);
|
|
||||||
await cache.SetAsync($"{ReturnUrlCachePrefix}{state}", finalReturnUrl, StateExpiration);
|
|
||||||
|
|
||||||
var authUrl = oidcService.GetAuthorizationUrl(state, nonce);
|
|
||||||
|
|
||||||
return Ok(new
|
|
||||||
{
|
|
||||||
authUrl,
|
|
||||||
message = $"Redirect to this URL to connect your {request.Provider} account"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[Route("/auth/callback/{provider}")]
|
[Route("/auth/callback/{provider}")]
|
||||||
[HttpGet, HttpPost]
|
[HttpGet, HttpPost]
|
||||||
@@ -194,7 +157,7 @@ public class ConnectionController(
|
|||||||
await cache.RemoveAsync(stateKey);
|
await cache.RemoveAsync(stateKey);
|
||||||
|
|
||||||
// Handle the flow based on state type
|
// Handle the flow based on state type
|
||||||
if (oidcState.FlowType == OidcFlowType.Connect && oidcState.AccountId.HasValue)
|
if (oidcState is { FlowType: OidcFlowType.Connect, AccountId: not null })
|
||||||
{
|
{
|
||||||
// Connection flow
|
// Connection flow
|
||||||
if (oidcState.DeviceId != null)
|
if (oidcState.DeviceId != null)
|
||||||
@@ -212,11 +175,10 @@ public class ConnectionController(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Store return URL if provided
|
// Store return URL if provided
|
||||||
if (!string.IsNullOrEmpty(oidcState.ReturnUrl) && oidcState.ReturnUrl != "/")
|
if (string.IsNullOrEmpty(oidcState.ReturnUrl) || oidcState.ReturnUrl == "/")
|
||||||
{
|
return await HandleLoginOrRegistration(provider, oidcService, callbackData);
|
||||||
var returnUrlKey = $"{ReturnUrlCachePrefix}{callbackData.State}";
|
var returnUrlKey = $"{ReturnUrlCachePrefix}{callbackData.State}";
|
||||||
await cache.SetAsync(returnUrlKey, oidcState.ReturnUrl, StateExpiration);
|
await cache.SetAsync(returnUrlKey, oidcState.ReturnUrl, StateExpiration);
|
||||||
}
|
|
||||||
|
|
||||||
return await HandleLoginOrRegistration(provider, oidcService, callbackData);
|
return await HandleLoginOrRegistration(provider, oidcService, callbackData);
|
||||||
}
|
}
|
||||||
|
@@ -55,6 +55,11 @@ const router = createRouter({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/auth/callback',
|
||||||
|
name: 'authCallback',
|
||||||
|
component: () => import('../views/callback.vue'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/:notFound(.*)',
|
path: '/:notFound(.*)',
|
||||||
name: 'errorNotFound',
|
name: 'errorNotFound',
|
||||||
|
@@ -49,7 +49,7 @@
|
|||||||
import { NCard, NList, NListItem, NThing, NAlert } from 'naive-ui'
|
import { NCard, NList, NListItem, NThing, NAlert } from 'naive-ui'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
|
|
||||||
const connectionsProviders = ['apple', 'google', 'microsoft', 'discord']
|
const connectionsProviders = ['apple', 'google', 'microsoft', 'discord', 'github', 'afdian']
|
||||||
const connections = ref<any[]>([])
|
const connections = ref<any[]>([])
|
||||||
|
|
||||||
const connectionsAddable = computed(() =>
|
const connectionsAddable = computed(() =>
|
||||||
|
9
DysonNetwork.Pass/Client/src/views/callback.vue
Normal file
9
DysonNetwork.Pass/Client/src/views/callback.vue
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex justify-center items-center">
|
||||||
|
<n-result status="success" title="Auth completed" description="Now you can close this tab" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script type="ts" setup>
|
||||||
|
import { NResult } from 'naive-ui';
|
||||||
|
</script>
|
Reference in New Issue
Block a user