Browse Source

Aded consent page for IDS.

pull/217/head
Halil İbrahim Kalkan 9 years ago
parent
commit
ff65d1520e
  1. 4
      Volo.Abp.sln
  2. 1
      src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/Login.cshtml.cs
  3. 38
      src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/_ScopeListItem.cshtml
  4. 76
      src/Volo.Abp.Account.Web.IdentityServer/Pages/Consent.cshtml
  5. 218
      src/Volo.Abp.Account.Web.IdentityServer/Pages/Consent.cshtml.cs
  6. 3
      src/Volo.Abp.Account.Web.IdentityServer/Pages/_ViewImports.cshtml
  7. 4
      src/Volo.Abp.Account.Web.IdentityServer/Volo.Abp.Account.Web.IdentityServer.csproj

4
Volo.Abp.sln

@ -296,9 +296,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MicroserviceDemo.TenancySer
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.MultiTenancy.HttpApi.Client", "src\Volo.Abp.MultiTenancy.HttpApi.Client\Volo.Abp.MultiTenancy.HttpApi.Client.csproj", "{76D24E2C-8DB0-48B7-9FC4-02231B8B9F39}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MicroserviceDemo.AuthServer", "src\MicroserviceDemo\MicroserviceDemo.AuthServer\MicroserviceDemo.AuthServer.csproj", "{A177B8B7-ACAD-4F75-B6D4-B72F7BC2E40A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MicroserviceDemo.AuthServer", "src\MicroserviceDemo\MicroserviceDemo.AuthServer\MicroserviceDemo.AuthServer.csproj", "{A177B8B7-ACAD-4F75-B6D4-B72F7BC2E40A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Account.Web.IdentityServer", "src\Volo.Abp.Account.Web.IdentityServer\Volo.Abp.Account.Web.IdentityServer.csproj", "{E4AB8A4F-BB59-4BDB-B915-877CE97D8113}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Account.Web.IdentityServer", "src\Volo.Abp.Account.Web.IdentityServer\Volo.Abp.Account.Web.IdentityServer.csproj", "{E4AB8A4F-BB59-4BDB-B915-877CE97D8113}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

1
src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/Login.cshtml.cs

@ -23,6 +23,7 @@ using Volo.Abp.Uow;
namespace Volo.Abp.Account.Web.Pages.Account
{
//TODO: Inherit from LoginModel of Account.Web project. We should design it as extensible.
public class IdsLoginModel : AccountModelBase
{
[HiddenInput]

38
src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/_ScopeListItem.cshtml

@ -0,0 +1,38 @@
@using Volo.Abp.Account.Web.Pages
@using Volo.Abp.Account.Web.Pages.Account
@model Volo.Abp.Account.Web.Pages.ConsentModel.ScopeViewModel
@* TODO: Should re-format this, just made copy/paste *@
<li class="list-group-item">
<label>
<input class="consent-scopecheck"
type="checkbox"
name="ScopesConsented"
id="scopes_@Model.Name"
value="@Model.Name"
checked="@Model.Checked"
disabled="@Model.Required" />
@if (Model.Required)
{
<input type="hidden"
name="ScopesConsented"
value="@Model.Name" />
}
<strong>@Model.DisplayName</strong>
@if (Model.Emphasize)
{
<span class="glyphicon glyphicon-exclamation-sign"></span>
}
</label>
@if (Model.Required)
{
<span><em>(required)</em></span>
}
@if (Model.Description != null)
{
<div class="consent-description">
<label for="scopes_@Model.Name">@Model.Description</label>
</div>
}
</li>

76
src/Volo.Abp.Account.Web.IdentityServer/Pages/Consent.cshtml

@ -0,0 +1,76 @@
@page
@using Volo.Abp.Account.Web.Pages
@using Volo.Abp.Account.Web.Pages.Account
@model ConsentModel
<abp-card id="IdentityServerConsentWrapper">
<abp-card-header>
<div class="row">
<div class="col-md-12">
<h2>
@if (Model.ClientLogoUrl != null)
{
<img src="@Model.ClientLogoUrl">
}
@Model.ClientName
<small>is requesting your permission</small>
</h2>
</div>
</div>
</abp-card-header>
<abp-card-body>
<form method="post" asp-page="/Account/Consent">
<input type="hidden" asp-for="ReturnUrl" />
<input type="hidden" asp-for="ReturnUrlHash" />
<div>Uncheck the permissions you do not wish to grant.</div>
@if (Model.IdentityScopes.Any())
{
<h3>Personal Information</h3>
<ul class="list-group">
@foreach (var scope in Model.IdentityScopes)
{
@Html.Partial("Account/_ScopeListItem", scope)
}
</ul>
}
@if (Model.ResourceScopes.Any())
{
<h3>Application Access</h3>
<ul class="list-group">
@foreach (var scope in Model.ResourceScopes)
{
@Html.Partial("Account/_ScopeListItem", scope)
}
</ul>
}
@if (Model.AllowRememberConsent)
{
<div class="form-check">
<label asp-for="@Model.ConsentInput.RememberConsent" class="form-check-label">
<input asp-for="@Model.ConsentInput.RememberConsent" class="form-check-input" />
<strong>Remember My Decision</strong>
</label>
</div>
}
<div>
<button name="UserDecision" value="yes" class="btn btn-primary" autofocus>Yes, Allow</button>
<button name="UserDecision" value="no" class="btn">No, Do Not Allow</button>
@if (Model.ClientUrl != null)
{
<a class="pull-right btn btn-secondary" target="_blank" href="@Model.ClientUrl">
<strong>@Model.ClientName</strong>
</a>
}
</div>
<div asp-validation-summary="All" class="text-danger"></div>
</form>
</abp-card-body>
</abp-card>

218
src/Volo.Abp.Account.Web.IdentityServer/Pages/Consent.cshtml.cs

@ -0,0 +1,218 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using IdentityServer4.Models;
using IdentityServer4.Services;
using IdentityServer4.Stores;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.RazorPages;
namespace Volo.Abp.Account.Web.Pages
{
//TODO: Move this into the Account folder!!!
public class ConsentModel : AbpPageModel
{
[HiddenInput]
[BindProperty(SupportsGet = true)]
public string ReturnUrl { get; set; }
[HiddenInput]
[BindProperty(SupportsGet = true)]
public string ReturnUrlHash { get; set; }
[BindProperty]
public ConsentInputModel ConsentInput { get; set; }
public string ClientName { get; set; }
public string ClientUrl { get; set; }
public string ClientLogoUrl { get; set; }
public bool AllowRememberConsent { get; set; }
public List<ScopeViewModel> IdentityScopes { get; set; }
public List<ScopeViewModel> ResourceScopes { get; set; }
private readonly IIdentityServerInteractionService _interaction;
private readonly IClientStore _clientStore;
private readonly IResourceStore _resourceStore;
public ConsentModel(
IIdentityServerInteractionService interaction,
IClientStore clientStore,
IResourceStore resourceStore)
{
_interaction = interaction;
_clientStore = clientStore;
_resourceStore = resourceStore;
}
public async Task OnGet()
{
var request = await _interaction.GetAuthorizationContextAsync(ReturnUrl);
if (request == null)
{
throw new ApplicationException($"No consent request matching request: {ReturnUrl}");
}
var client = await _clientStore.FindEnabledClientByIdAsync(request.ClientId);
if (client == null)
{
throw new ApplicationException($"Invalid client id: {request.ClientId}");
}
var resources = await _resourceStore.FindEnabledResourcesByScopeAsync(request.ScopesRequested);
if (resources == null || (!resources.IdentityResources.Any() && !resources.ApiResources.Any()))
{
throw new ApplicationException($"No scopes matching: {request.ScopesRequested.Aggregate((x, y) => x + ", " + y)}");
}
ConsentInput = new ConsentInputModel
{
RememberConsent = true,
ScopesConsented = new List<string>()
};
ClientName = client.ClientId; //TODO: Consider to create a ClientInfoModel
ClientUrl = client.ClientUri;
ClientLogoUrl = client.LogoUri;
AllowRememberConsent = client.AllowRememberConsent;
IdentityScopes = resources.IdentityResources.Select(x => CreateScopeViewModel(x, true)).ToList();
ResourceScopes = resources.ApiResources.SelectMany(x => x.Scopes).Select(x => CreateScopeViewModel(x, true)).ToList();
if (resources.OfflineAccess)
{
ResourceScopes = ResourceScopes.Union(new[] {GetOfflineAccessScope(true)}).ToList();
}
}
public async Task<IActionResult> OnPost(string userDecision)
{
var result = await ProcessConsentAsync();
if (result.IsRedirect)
{
return Redirect(result.RedirectUri);
}
if (result.HasValidationError)
{
ModelState.AddModelError("", result.ValidationError);
}
throw new ApplicationException("Error: ");
}
private async Task<ProcessConsentResult> ProcessConsentAsync()
{
var result = new ProcessConsentResult();
ConsentResponse grantedConsent = null;
if (ConsentInput.UserDecision == "no")
{
grantedConsent = ConsentResponse.Denied;
}
else
{
if (ConsentInput.ScopesConsented != null && ConsentInput.ScopesConsented.Any())
{
var scopes = ConsentInput.ScopesConsented;
grantedConsent = new ConsentResponse
{
RememberConsent = ConsentInput.RememberConsent,
ScopesConsented = scopes.ToArray()
};
}
else
{
result.ValidationError = "You must pick at least one permission";
}
}
if (grantedConsent != null)
{
// validate return url is still valid
var request = await _interaction.GetAuthorizationContextAsync(ReturnUrl);
if (request == null) return result;
// communicate outcome of consent back to identityserver
await _interaction.GrantConsentAsync(request, grantedConsent);
// indicate that's it ok to redirect back to authorization endpoint
result.RedirectUri = ReturnUrl; //TODO: ReturnUrlHash?
}
return result;
}
private ScopeViewModel CreateScopeViewModel(IdentityResource identity, bool check)
{
return new ScopeViewModel
{
Name = identity.Name,
DisplayName = identity.DisplayName,
Description = identity.Description,
Emphasize = identity.Emphasize,
Required = identity.Required,
Checked = check || identity.Required
};
}
public ScopeViewModel CreateScopeViewModel(Scope scope, bool check)
{
return new ScopeViewModel
{
Name = scope.Name,
DisplayName = scope.DisplayName,
Description = scope.Description,
Emphasize = scope.Emphasize,
Required = scope.Required,
Checked = check || scope.Required
};
}
private ScopeViewModel GetOfflineAccessScope(bool check)
{
return new ScopeViewModel
{
Name = IdentityServer4.IdentityServerConstants.StandardScopes.OfflineAccess,
DisplayName = "Offline Access", //TODO: Localize
Description = "Access to your applications and resources, even when you are offline",
Emphasize = true,
Checked = check
};
}
public class ConsentInputModel
{
public string UserDecision { get; set; }
public List<string> ScopesConsented { get; set; }
public bool RememberConsent { get; set; }
}
public class ScopeViewModel
{
public string Name { get; set; }
public string DisplayName { get; set; }
public string Description { get; set; }
public bool Emphasize { get; set; }
public bool Required { get; set; }
public bool Checked { get; set; }
}
public class ProcessConsentResult
{
public bool IsRedirect => RedirectUri != null;
public string RedirectUri { get; set; }
public bool HasValidationError => ValidationError != null;
public string ValidationError { get; set; }
}
}
}

3
src/Volo.Abp.Account.Web.IdentityServer/Pages/_ViewImports.cshtml

@ -0,0 +1,3 @@
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap

4
src/Volo.Abp.Account.Web.IdentityServer/Volo.Abp.Account.Web.IdentityServer.csproj

@ -19,6 +19,10 @@
<EmbeddedResource Include="Pages\**\*.*" Exclude="*.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="Pages\_ViewImports.cshtml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Account.Web\Volo.Abp.Account.Web.csproj" />
<ProjectReference Include="..\Volo.Abp.IdentityServer.Domain\Volo.Abp.IdentityServer.Domain.csproj" />

Loading…
Cancel
Save