Comments (7)
Hello and thanks for the feedback (and for purchasing the book as well).
Regarding your query, you can use OpenIddict with standard tokens without problems, or even ditch OpenIddict completely and implement your own token provider: the OpenGameList client app does not require tokens to be JWTs, nor it does make any attempt to read or decrypt it: as you can easily see, it just stores the token locally and send it back to the server by appending it on the Authorization header. As a matter of fact, they are opaque to the client (just as @PinpointTownes says).
Of course migrating from JWTs to standard tokens will require a minor refactor of Chapter 8 and 9, but this is quite easy to do as long as you understand the underlying logic and follow the OpenIddict implementation samples. That said, in case you need help with this, I can gladly help you with the transition from JWT to standard tokens.
As for the fact that the OpenIddictUser is not there anymore, I'm glad they now enforce the usage of the standard IdentityUser class, thus enforcing the default .NET Core Identity auth pattern.
from aspdotnet-core-and-angular-2.
As a side note, I would like to clarify that (from the thread you mentioned) it doesn't look like OpenIddict is departing from using JWTs. Here's what happened there:
- The OP asked for the missing OpenIddictUser identity class (which has been removed)
- The project owner pointed him to standard code samples (which use the standard IdentityUser class instead, AND the standard tokens)
- The OP asks for JWT samples, since the given samples don't use JWTs and he needs them to since he's decoding them with his client app.
- The project owner replied that the given samples are viable regardless of token type, since it should be opaque to clients: he also warns the OP about having the client app rely to JWTs and/or decrypt JWTs, since it's not what you should do.
To keep it short, all we need to do is to use the given samples (with a grain of salt) and replace OpenIddictUser with IdentityUser, without worrying about JWTs.
from aspdotnet-core-and-angular-2.
- The OP asked for the missing OpenIddictUser class (which has been removed)
- The project owner pointed him to standard code samples (which use standard tokens)
- The OP asks for JWT samples
- The project owner replied that the given samples are viable regardless of token type, since it should be - opaque to clients.
Yup, exactly that 😄
from aspdotnet-core-and-angular-2.
Thanks, Darkseal! I would love a link to an updated Chapter 10 project with the changes if that is possible.
from aspdotnet-core-and-angular-2.
Have you completed the refactoring of Chapter 8 and 9? We would for sure appreciate getting access to the new source code! Thanks
from aspdotnet-core-and-angular-2.
After hours of effort, here's the working solution you can try if you run into the issue while following along this book:
Delete Migrations folder and run: dotnet ef database drop
Then run: dotnet ef migrations add "OpenIddict" -o "Data\Migrations"
Project.json:
{
"dependencies": {
"AspNet.Security.OAuth.Validation": "1.0.0-",
"Microsoft.AspNetCore.Authentication.JwtBearer": "1.0.0",
"Microsoft.AspNetCore.Diagnostics": "1.1.0",
"Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore": "1.1.0",
"Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.1.0",
"Microsoft.AspNetCore.Mvc": "1.1.0",
"Microsoft.AspNetCore.Routing": "1.1.0",
"Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
"Microsoft.AspNetCore.StaticFiles": "1.1.0",
"Microsoft.EntityFrameworkCore": "1.1.0",
"Microsoft.EntityFrameworkCore.Design": "1.1.0",
"Microsoft.EntityFrameworkCore.SqlServer": "1.1.0",
"Microsoft.EntityFrameworkCore.SqlServer.Design": "1.1.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
"Microsoft.Extensions.Configuration.FileExtensions": "1.1.0",
"Microsoft.Extensions.Configuration.Json": "1.1.0",
"Microsoft.Extensions.Logging": "1.1.0",
"Microsoft.Extensions.Logging.Console": "1.1.0",
"Microsoft.Extensions.Logging.Debug": "1.1.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0",
"Microsoft.IdentityModel.Tokens": "5.1.3",
"Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.1.0",
"Newtonsoft.Json": "9.0.1",
"OpenIddict": "1.0.0-",
"OpenIddict.EntityFrameworkCore": "1.0.0-",
"OpenIddict.Mvc": "1.0.0-",
"System.IdentityModel.Tokens.Jwt": "5.1.3",
"TinyMapper": "2.0.8"
},
"tools": {
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.1.0-preview4-final",
"Microsoft.EntityFrameworkCore.Tools.DotNet": "1.0.0-preview3-final"
},
"frameworks": {
"net461": {}
},
"buildOptions": {
"emitEntryPoint": true,
"preserveCompilationContext": true
},
"publishOptions": {
"include": [
"wwwroot",
"Views",
"Areas/**/Views",
"appsettings.json",
"web.config"
]
},
"scripts": {
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
}
}
appsettings.json
{
"Authentication": {
"OpenIddict": {
"ApplicationId": "OpenGameList",
"DisplayName": "OpenGameList",
"AuthorizationEndPoint": "/api/connect/authorize",
"TokenEndPoint": "/api/connect/token",
"ClientId": "OpenGameList",
"ClientSecret": "1234567890_my_client_secret",
"Authority": "http://localhost:14600/"
}
},
"Data": {
"DefaultConnection": {
"ConnectionString": "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=OpenGameList;Integrated Security=True;MultipleActiveResultSets=True"
}
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"StaticFiles": {
"Headers": {
"Cache-Control": "no-cache, no-store",
"Pragma": "no-cache",
"Expires": "-1"
}
}
}
Startup.cs
using System;
using System.IdentityModel.Tokens.Jwt;
using AspNet.Security.OpenIdConnect.Primitives;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using OpenGameListWebApp.Data;
using Nelibur.ObjectMapper;
using OpenGameListWebApp.Data.Items;
using OpenGameListWebApp.Data.Users;
using OpenGameListWebApp.ViewModels;
using OpenIddict.Core;
using OpenIddict.Models;
namespace OpenGameList
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add a reference to the Configuration object for DI
services.AddSingleton<IConfiguration>(c => Configuration);
// Add framework services.
services.AddMvc();
// Add ApplicationDbContext.
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]);
// Register the entity sets needed by OpenIddict.
// Note: use the generic overload if you need
// to replace the default OpenIddict entities.
options.UseOpenIddict();
});
// Add EntityFramework's Identity support.
//services.AddEntityFramework();
// Add Identity Services & Stores
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.User.RequireUniqueEmail = true;
options.Password.RequireNonAlphanumeric = false;
options.Cookies.ApplicationCookie.AutomaticChallenge = false;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
// Configure Identity to use the same JWT claims as OpenIddict instead
// of the legacy WS-Federation claims it uses by default (ClaimTypes),
// which saves you from doing the mapping in your authorization controller.
services.Configure<IdentityOptions>(options =>
{
options.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name;
options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject;
options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role;
});
// Register OpenIddict services, including the default Entity Framework stores.
services.AddOpenIddict(options =>
{
// Register the ASP.NET Core MVC binder used by OpenIddict.
// Note: if you don't call this method, you won't be able to bind OpenIdConnectRequest
// or OpenIdConnectResponse parameters.
options.AddMvcBinders();
// Registers the Entity Framework stores.
options.AddEntityFrameworkCoreStores<ApplicationDbContext>();
// Use JWT access tokens instead of the default encrypted format
options.UseJsonWebTokens();
// Set custom token endpoint. Default is /connect/token
options.EnableTokenEndpoint(Configuration["Authentication:OpenIddict:TokenEndPoint"]);
// Set a custom auth endpoint (default is /connect/authorize)
options.EnableAuthorizationEndpoint(Configuration["Authentication:OpenIddict:AuthorizationEndPoint"]);
// Allow client applications to use the grant_type = password flow
options.AllowPasswordFlow();
// Enable support for both authorization & implicit flows
options.AllowAuthorizationCodeFlow();
options.AllowImplicitFlow();
// Allow the client to refresh tokens
options.AllowRefreshTokenFlow();
// During development, you can disable the HTTPS requirement
options.DisableHttpsRequirement();
// Register a new ephemeral key for development.
// We will register a X.509 certificate in production.
options.AddEphemeralSigningKey();
});
// Add ApplicationDbContext's DbSeeder
services.AddSingleton<DbSeeder>();
services.AddSingleton<OpenIddictApplicationManager<OpenIddictApplication>>();
services.AddSingleton < SignInManager<ApplicationUser>>();
services.AddSingleton<UserManager<ApplicationUser>>();
services.AddOptions();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, DbSeeder dbSeeder)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
// Configure a rewrite rule to auto-lookup for standard default files such as index.html.
app.UseDefaultFiles();
// Serve static files (html, css, js, images & more). See also the following URL:
// https://docs.asp.net/en/latest/fundamentals/static-files.html for further reference.
app.UseStaticFiles(new StaticFileOptions()
{
OnPrepareResponse = (context) =>
{
// Disable caching for all static files.
context.Context.Response.Headers["Cache-Control"] = Configuration["StaticFiles:Headers:Cache-Control"];
context.Context.Response.Headers["Pragma"] = Configuration["StaticFiles:Headers:Pragma"];
context.Context.Response.Headers["Expires"] = Configuration["StaticFiles:Headers:Expires"];
}
});
app.UseIdentity();
app.UseOAuthValidation();
// Add a custom Jwt Provider to generate Tokens
//app.UseJwtProvider();
// Add OpenIddict middleware
// Note: UseOpenIddict() must be registered after app.UseIdentity() and the external social providers
app.UseOpenIddict();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap.Clear();
// Add the Jwt Bearer Header Authentication to validate Tokens
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
RequireHttpsMetadata = false,
// Allows the JWT bearer middleware to download the signing key
Authority = Configuration["Authentication:OpenIddict:Authority"],
Audience = "resource_server",
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = OpenIdConnectConstants.Claims.Name,
RoleClaimType = OpenIdConnectConstants.Claims.Role
}
});
// Add MVC to the pipeline
app.UseMvc();
// TinyMapper binding configuration
TinyMapper.Bind<Item, ItemViewModel>();
// Seed the Database (if needed)
try
{
dbSeeder.SeedAsync().Wait();
}
catch (AggregateException e)
{
throw new Exception(e.ToString());
}
}
}
}
ApplicationDbContext.cs
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using OpenGameListWebApp.Data.Comments;
using OpenGameListWebApp.Data.Items;
using OpenGameListWebApp.Data.Users;
using OpenIddict.Models;
namespace OpenGameListWebApp.Data
{
public class ApplicationDbContext : IdentityDbContext
{
#region Constructor
public ApplicationDbContext(DbContextOptions options): base(options)
{
}
#endregion Constructor
#region Methods
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ApplicationUser>().ToTable("Users");
modelBuilder.Entity<ApplicationUser>()
.HasMany(u => u.Items)
.WithOne(i => i.Author);
modelBuilder.Entity<ApplicationUser>()
.HasMany(u => u.Comments)
.WithOne(c => c.Author)
.HasPrincipalKey(u => u.Id);
modelBuilder.Entity<Item>().ToTable("Items");
modelBuilder.Entity<Item>().Property(i => i.Id).ValueGeneratedOnAdd();
modelBuilder.Entity<Item>().HasOne(i => i.Author).WithMany(u => u.Items);
modelBuilder.Entity<Item>().HasMany(i => i.Comments).WithOne(c => c.Item);
modelBuilder.Entity<Comment>().ToTable("Comments");
modelBuilder.Entity<Comment>()
.HasOne(c => c.Author)
.WithMany(u => u.Comments)
.HasForeignKey(c => c.UserId)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Comment>().HasOne(c => c.Item).WithMany(i => i.Comments);
modelBuilder.Entity<Comment>().HasOne(c => c.Parent).WithMany(c => c.Children);
modelBuilder.Entity<Comment>().HasMany(c => c.Children).WithOne(c => c.Parent);
}
#endregion
#region Properties
public DbSet<Item> Items { get; set; }
public DbSet<Comment> Comments { get; set; }
public DbSet<OpenIddictApplication> Applications { get; set; }
#endregion Properties
}
}
Make sure to have below in DbSeeder.cs
public async Task SeedAsync()
{
// Create the Db if it doesn’t exist
DbContext.Database.EnsureCreated();
// Create default Application
if (!DbContext.Applications.Any()) CreateApplication();
// Create default Users
if (await DbContext.Users.CountAsync() == 0) await CreateUsersAsync();
// Create default Items (if there are none) and Comments
if (await DbContext.Items.CountAsync() == 0) CreateItems();
}
#endregion Public Methods
#region Seed Methods
private void CreateApplication()
{
DbContext.Applications.Add(new OpenIddictApplication
{
Id = Configuration["Authentication:OpenIddict:ApplicationId"],
DisplayName = Configuration["Authentication:OpenIddict:DisplayName"],
RedirectUri = Configuration["Authentication:OpenIddict:TokenEndPoint"],
LogoutRedirectUri = "/",
ClientId = Configuration["Authentication:OpenIddict:ClientId"],
ClientSecret = Crypto.HashPassword(Configuration["Authentication:OpenIddict:ClientSecret"]),
Type = OpenIddictConstants.ClientTypes.Public
});
DbContext.SaveChanges();
}
Then add ConnectController.cs
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using AspNet.Security.OpenIdConnect.Extensions;
using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using OpenGameListWebApp.Data.Users;
using OpenGameListWebApp.ViewModels;
using OpenIddict.Core;
using OpenIddict.Models;
namespace OpenGameListWebApp.Controllers
{
[Route("api/[controller]")]
public class ConnectController : Controller
{
private readonly OpenIddictApplicationManager _applicationManager;
private readonly IOptions _identityOptions;
private readonly SignInManager _signInManager;
private readonly UserManager _userManager;
public ConnectController(
OpenIddictApplicationManager<OpenIddictApplication> applicationManager,
IOptions<IdentityOptions> identityOptions,
SignInManager<ApplicationUser> signInManager,
UserManager<ApplicationUser> userManager)
{
_applicationManager = applicationManager;
_identityOptions = identityOptions;
_signInManager = signInManager;
_userManager = userManager;
}
// Note: to support interactive flows like the code flow,
// you must provide your own authorization endpoint action:
[Authorize, HttpGet("authorize")]
public async Task<IActionResult> Authorize(OpenIdConnectRequest request)
{
Debug.Assert(request.IsAuthorizationRequest(),
"The OpenIddict binder for ASP.NET Core MVC is not registered. " +
"Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");
// Retrieve the application details from the database.
var application = await _applicationManager.FindByClientIdAsync(request.ClientId, HttpContext.RequestAborted);
if (application == null)
{
return BadRequest(new OpenIdConnectResponse
{
Error = OpenIdConnectConstants.Errors.InvalidClient,
ErrorDescription = "Details concerning the calling client application cannot be found in the database."
});
}
// Flow the request_id to allow OpenIddict to restore
// the original authorization request from the cache.
return new JsonResult(new AuthorizeViewModel
{
ApplicationName = application.DisplayName,
RequestId = request.RequestId,
Scope = request.Scope
}, DefaultJsonSettings);
}
[Authorize]
[HttpPost("authorize"), ValidateAntiForgeryToken]
public async Task<IActionResult> Accept(OpenIdConnectRequest request)
{
Debug.Assert(request.IsAuthorizationRequest(),
"The OpenIddict binder for ASP.NET Core MVC is not registered. " +
"Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");
// Retrieve the profile of the logged in user.
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return BadRequest(new OpenIdConnectResponse
{
Error = OpenIdConnectConstants.Errors.ServerError,
ErrorDescription = "An internal error has occurred"
});
}
// Create a new authentication ticket.
var ticket = await CreateTicketAsync(request, user);
// Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
}
[HttpPost("logout"), ValidateAntiForgeryToken]
public async Task<IActionResult> Logout()
{
// Ask ASP.NET Core Identity to delete the local and external cookies created
// when the user agent is redirected from the external identity provider
// after a successful authentication flow (e.g Google or Facebook).
await _signInManager.SignOutAsync();
// Returning a SignOutResult will ask OpenIddict to redirect the user agent
// to the post_logout_redirect_uri specified by the client application.
return SignOut(OpenIdConnectServerDefaults.AuthenticationScheme);
}
[HttpPost("token"), Produces("application/json")]
public async Task<IActionResult> Exchange(OpenIdConnectRequest request)
{
Debug.Assert(request.IsTokenRequest(),
"The OpenIddict binder for ASP.NET Core MVC is not registered. " +
"Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");
if (request.IsPasswordGrantType())
{
var user = await _userManager.FindByNameAsync(request.Username);
if (user == null)
{
return BadRequest(new OpenIdConnectResponse
{
Error = OpenIdConnectConstants.Errors.InvalidGrant,
ErrorDescription = "The username/password couple is invalid."
});
}
// Ensure the user is allowed to sign in.
if (!await _signInManager.CanSignInAsync(user))
{
return BadRequest(new OpenIdConnectResponse
{
Error = OpenIdConnectConstants.Errors.InvalidGrant,
ErrorDescription = "The specified user is not allowed to sign in."
});
}
// Reject the token request if two-factor authentication has been enabled by the user.
if (_userManager.SupportsUserTwoFactor && await _userManager.GetTwoFactorEnabledAsync(user))
{
return BadRequest(new OpenIdConnectResponse
{
Error = OpenIdConnectConstants.Errors.InvalidGrant,
ErrorDescription = "The specified user is not allowed to sign in."
});
}
// Ensure the user is not already locked out.
if (_userManager.SupportsUserLockout && await _userManager.IsLockedOutAsync(user))
{
return BadRequest(new OpenIdConnectResponse
{
Error = OpenIdConnectConstants.Errors.InvalidGrant,
ErrorDescription = "The username/password couple is invalid."
});
}
// Ensure the password is valid.
if (!await _userManager.CheckPasswordAsync(user, request.Password))
{
if (_userManager.SupportsUserLockout)
{
await _userManager.AccessFailedAsync(user);
}
return BadRequest(new OpenIdConnectResponse
{
Error = OpenIdConnectConstants.Errors.InvalidGrant,
ErrorDescription = "The username/password couple is invalid."
});
}
if (_userManager.SupportsUserLockout)
{
await _userManager.ResetAccessFailedCountAsync(user);
}
// Create a new authentication ticket.
var ticket = await CreateTicketAsync(request, user);
return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
}
else if (request.IsAuthorizationCodeGrantType() || request.IsRefreshTokenGrantType())
{
// Retrieve the claims principal stored in the authorization code/refresh token.
var info = await HttpContext.Authentication.GetAuthenticateInfoAsync(
OpenIdConnectServerDefaults.AuthenticationScheme);
// Retrieve the user profile corresponding to the authorization code/refresh token.
// Note: if you want to automatically invalidate the authorization code/refresh token
// when the user password/roles change, use the following line instead:
// var user = _signInManager.ValidateSecurityStampAsync(info.Principal);
var user = await _userManager.GetUserAsync(info.Principal);
if (user == null)
{
return BadRequest(new OpenIdConnectResponse
{
Error = OpenIdConnectConstants.Errors.InvalidGrant,
ErrorDescription = "The token is no longer valid."
});
}
// Ensure the user is still allowed to sign in.
if (!await _signInManager.CanSignInAsync(user))
{
return BadRequest(new OpenIdConnectResponse
{
Error = OpenIdConnectConstants.Errors.InvalidGrant,
ErrorDescription = "The user is no longer allowed to sign in."
});
}
// Create a new authentication ticket, but reuse the properties stored in the
// authorization code/refresh token, including the scopes originally granted.
var ticket = await CreateTicketAsync(request, user, info.Properties);
return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
}
return BadRequest(new OpenIdConnectResponse
{
Error = OpenIdConnectConstants.Errors.UnsupportedGrantType,
ErrorDescription = "The specified grant type is not supported."
});
}
private async Task<AuthenticationTicket> CreateTicketAsync(
OpenIdConnectRequest request,
ApplicationUser user,
AuthenticationProperties properties = null)
{
// Create a new ClaimsPrincipal containing the claims that
// will be used to create an id_token, a token or a code.
var principal = await _signInManager.CreateUserPrincipalAsync(user);
// Create a new authentication ticket holding the user identity.
var ticket = new AuthenticationTicket(principal, properties,
OpenIdConnectServerDefaults.AuthenticationScheme);
if (!request.IsAuthorizationCodeGrantType() && !request.IsRefreshTokenGrantType())
{
// Set the list of scopes granted to the client application.
// Note: the offline_access scope must be granted
// to allow OpenIddict to return a refresh token.
ticket.SetScopes(new[]
{
OpenIdConnectConstants.Scopes.OpenId,
OpenIdConnectConstants.Scopes.Email,
OpenIdConnectConstants.Scopes.Profile,
OpenIdConnectConstants.Scopes.OfflineAccess,
OpenIddictConstants.Scopes.Roles
}.Intersect(request.GetScopes()));
}
ticket.SetResources("resource_server");
// Note: by default, claims are NOT automatically included in the access and identity tokens.
// To allow OpenIddict to serialize them, you must attach them a destination, that specifies
// whether they should be included in access tokens, in identity tokens or in both.
foreach (var claim in ticket.Principal.Claims)
{
// Never include the security stamp in the access and identity tokens, as it's a secret value.
if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType)
{
continue;
}
// Always include the user identifier in the
// access token and the identity token.
if (claim.Type == OpenIdConnectConstants.Claims.Name)
{
claim.SetDestinations(OpenIdConnectConstants.Destinations.AccessToken,
OpenIdConnectConstants.Destinations.IdentityToken);
}
// Include the role claims, but only if the "roles" scope was requested.
else if (claim.Type == OpenIdConnectConstants.Claims.Role && ticket.HasScope(OpenIddictConstants.Scopes.Roles))
{
claim.SetDestinations(OpenIdConnectConstants.Destinations.AccessToken,
OpenIdConnectConstants.Destinations.IdentityToken);
}
var destinations = new List<string>
{
OpenIdConnectConstants.Destinations.AccessToken
};
// Only add the iterated claim to the id_token if the corresponding scope was granted to the client application.
// The other claims will only be added to the access_token, which is encrypted when using the default format.
if ((claim.Type == OpenIdConnectConstants.Claims.Name && ticket.HasScope(OpenIdConnectConstants.Scopes.Profile)) ||
(claim.Type == OpenIdConnectConstants.Claims.Email && ticket.HasScope(OpenIdConnectConstants.Scopes.Email)) ||
(claim.Type == OpenIdConnectConstants.Claims.Role && ticket.HasScope(OpenIddictConstants.Claims.Roles)))
{
destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken);
}
claim.SetDestinations(destinations);
}
return ticket;
}
/// <summary>
/// Returns a suitable JsonSerializerSettings object that can be used to generate the JsonResult return value for this Controller's methods.
/// </summary>
private JsonSerializerSettings DefaultJsonSettings => new JsonSerializerSettings()
{
Formatting = Formatting.Indented
};
}
}
ApplicationUser.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using OpenGameListWebApp.Data.Comments;
using OpenGameListWebApp.Data.Items;
namespace OpenGameListWebApp.Data.Users
{
public class ApplicationUser : IdentityUser
{
#region Constructor
public ApplicationUser()
{
}
#endregion
#region Related Properties
/// <summary>
/// A list of items written by this user: this property will be loaded on first use using EF's lazy loading feature.
/// </summary>
public virtual List<Item> Items { get; set; }
/// <summary>
/// A list of comments written by this user: this property will be loaded on first use using EF's lazy loading feature.
/// </summary>
public virtual List<Comment> Comments { get; set; }
#endregion Related Properties
#region Properties
public string DisplayName { get; set; }
public string Notes { get; set; }
[Required]
public int Type { get; set; }
[Required]
public int Flags { get; set; }
[Required]
public DateTime CreatedDate { get; set; }
[Required]
public DateTime LastModifiedDate { get; set; }
#endregion Properties
}
}
That should do it.
from aspdotnet-core-and-angular-2.
@ttchongtc , kudos and many thanks for the great work!!!
from aspdotnet-core-and-angular-2.
Related Issues (13)
- Code won't compile because of some typescript error HOT 9
- Chapter 6: ng2-bootstrap TypeError HOT 2
- Loading all js libraries on initial load HOT 1
- Chapter 8: AccountsController - facebook login not working with IE 11. HOT 5
- OpenIddict refresh required on VS2017 code HOT 2
- Reference issues working the example with latest preview tools and versions of TS and Angular HOT 1
- post script typings install doesn't work HOT 2
- Can't login after password changing. HOT 1
- Does not build & run using latest version of .net HOT 2
- Stuck on "Loading..." HOT 1
- Bad request with authservice.get() HOT 1
- user.identity.isauthenticated always false ??? HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from aspdotnet-core-and-angular-2.