identityserver4测试

TangShanKaiPing
wanggang 6 years ago
parent 35e4caa723
commit 93c287bab1

@ -28,7 +28,7 @@
@Html.AntiForgeryToken()
<ul class="nav navbar-nav">
<li>
<a href="@Url.Action("Index", "Account", new { area = "" })">@User.Identity.Name</a>
<a href="@Url.Action("Index", "Account", new { area = "" })">@(User.Identity.Name ?? Context.User?.FindFirst("name")?.Value)</a>
</li>
<li>
<a href="@Url.Action("Logout", "Account", new { area = "" })">退出</a>

@ -87,12 +87,9 @@ namespace StudyCenter.Controllers
}
[Authorize]
public IActionResult Login(string returnUrl = null)
public IActionResult Login()
{
var fullReturnUrl = Url.GetFullUrl(returnUrl ?? "~");
var loginUrl = this._configuration["usercenter:login"];
var url = loginUrl.SetParam(nameof(returnUrl), fullReturnUrl);
return Redirect(url);
return RedirectToAction("Index", "Home");
}
[AllowAnonymous]

@ -4,7 +4,7 @@
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:8082",
"sslPort": 44382
"sslPort": 0
}
},
"profiles": {

@ -12,6 +12,7 @@ using Infrastructure.Sms;
using Infrastructure.Web;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
@ -35,42 +36,54 @@ namespace StudyCenter
public override void AddAuthentication(IServiceCollection services)
{
//JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddCookie("Cookies", o =>
{
o.Events = new CookieAuthenticationEvents
{
OnValidatePrincipal = ValidatePrincipal
};
})
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "http://localhost";
options.RequireHttpsMetadata = false;
options.ClientId = "mvc";
options.SaveTokens = true;
options.Events = new OpenIdConnectEvents
{
OnTicketReceived = o =>
{
return Task.CompletedTask;
}
};
});
}
public override Task ValidatePrincipal(CookieValidatePrincipalContext arg)
{
return Task.Run(() =>
{
//var userRepo = arg.HttpContext.RequestServices.GetService<IRepository<User>>();
var userRepo = arg.HttpContext.RequestServices.GetService<IRepository<User>>();
//var userName = arg.Principal.Identity.Name;
//var userPermissions = userRepo.ReadOnlyTable().Where(o => o.UserName == userName)
// .SelectMany(o => o.UserRoles)
// .Select(o => o.Role)
// .SelectMany(o => o.RolePermissions)
// .Select(o => o.Permission.Number)
// .ToList();
//var currentPermissions = arg.Principal.Claims.Where(o => o.Type == "Role").Select(o => o.Value).ToList();
//if (!currentPermissions.SequenceEqual(userPermissions))
//{
// arg.HttpContext.SignOutAsync();
// arg.HttpContext.SignIn(userName, userPermissions, arg.Properties.IsPersistent);
//}
});
var userName = arg.Principal.FindFirst("name")?.Value;
var userPermissions = userRepo.ReadOnlyTable().Where(o => o.UserName == userName)
.SelectMany(o => o.UserRoles)
.Select(o => o.Role)
.SelectMany(o => o.RolePermissions)
.Select(o => o.Permission.Number)
.ToList();
var currentPermissions = arg.Principal.Claims.Where(o => o.Type == "Role").Select(o => o.Value).ToList();
if (!currentPermissions.SequenceEqual(userPermissions))
{
arg.HttpContext.SignOutAsync();
arg.HttpContext.SignIn(userName, userPermissions, arg.Properties.IsPersistent);
}
return Task.CompletedTask;
}
public override void OnModelCreating(ModelBuilder modelBuilder)

@ -0,0 +1,74 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using IdentityServer4.Services;
using IdentityServer4.Stores;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
namespace IdentityServer4.Quickstart.UI
{
/// <summary>
/// This controller processes the consent UI
/// </summary>
[SecurityHeaders]
public class ConsentController : Controller
{
private readonly ConsentService _consent;
public ConsentController(
IIdentityServerInteractionService interaction,
IClientStore clientStore,
IResourceStore resourceStore,
ILogger<ConsentController> logger)
{
_consent = new ConsentService(interaction, clientStore, resourceStore, logger);
}
/// <summary>
/// Shows the consent screen
/// </summary>
/// <param name="returnUrl"></param>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> Index(string returnUrl)
{
var vm = await _consent.BuildViewModelAsync(returnUrl);
if (vm != null)
{
return View("Index", vm);
}
return View("Error");
}
/// <summary>
/// Handles the consent screen postback
/// </summary>
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Index(ConsentInputModel model)
{
var result = await _consent.ProcessConsent(model);
if (result.IsRedirect)
{
return Redirect(result.RedirectUri);
}
if (result.HasValidationError)
{
ModelState.AddModelError("", result.ValidationError);
}
if (result.ShowView)
{
return View("Index", result.ViewModel);
}
return View("Error");
}
}
}

@ -0,0 +1,16 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using System.Collections.Generic;
namespace IdentityServer4.Quickstart.UI
{
public class ConsentInputModel
{
public string Button { get; set; }
public IEnumerable<string> ScopesConsented { get; set; }
public bool RememberConsent { get; set; }
public string ReturnUrl { get; set; }
}
}

@ -0,0 +1,16 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServer4.Quickstart.UI
{
public class ConsentOptions
{
public static bool EnableOfflineAccess = true;
public static string OfflineAccessDisplayName = "Offline Access";
public static string OfflineAccessDescription = "Access to your applications and resources, even when you are offline";
public static readonly string MustChooseOneErrorMessage = "You must pick at least one permission";
public static readonly string InvalidSelectionErrorMessage = "Invalid selection";
}
}

@ -0,0 +1,191 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using IdentityServer4.Models;
using IdentityServer4.Services;
using IdentityServer4.Stores;
using Microsoft.Extensions.Logging;
using System.Linq;
using System.Threading.Tasks;
namespace IdentityServer4.Quickstart.UI
{
public class ConsentService
{
private readonly IClientStore _clientStore;
private readonly IResourceStore _resourceStore;
private readonly IIdentityServerInteractionService _interaction;
private readonly ILogger _logger;
public ConsentService(
IIdentityServerInteractionService interaction,
IClientStore clientStore,
IResourceStore resourceStore,
ILogger logger)
{
_interaction = interaction;
_clientStore = clientStore;
_resourceStore = resourceStore;
_logger = logger;
}
public async Task<ProcessConsentResult> ProcessConsent(ConsentInputModel model)
{
var result = new ProcessConsentResult();
ConsentResponse grantedConsent = null;
// user clicked 'no' - send back the standard 'access_denied' response
if (model.Button == "no")
{
grantedConsent = ConsentResponse.Denied;
}
// user clicked 'yes' - validate the data
else if (model.Button == "yes" && model != null)
{
// if the user consented to some scope, build the response model
if (model.ScopesConsented != null && model.ScopesConsented.Any())
{
var scopes = model.ScopesConsented;
if (ConsentOptions.EnableOfflineAccess == false)
{
scopes = scopes.Where(x => x != IdentityServer4.IdentityServerConstants.StandardScopes.OfflineAccess);
}
grantedConsent = new ConsentResponse
{
RememberConsent = model.RememberConsent,
ScopesConsented = scopes.ToArray()
};
}
else
{
result.ValidationError = ConsentOptions.MustChooseOneErrorMessage;
}
}
else
{
result.ValidationError = ConsentOptions.InvalidSelectionErrorMessage;
}
if (grantedConsent != null)
{
// validate return url is still valid
var request = await _interaction.GetAuthorizationContextAsync(model.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 = model.ReturnUrl;
}
else
{
// we need to redisplay the consent UI
result.ViewModel = await BuildViewModelAsync(model.ReturnUrl, model);
}
return result;
}
public async Task<ConsentViewModel> BuildViewModelAsync(string returnUrl, ConsentInputModel model = null)
{
var request = await _interaction.GetAuthorizationContextAsync(returnUrl);
if (request != null)
{
var client = await _clientStore.FindEnabledClientByIdAsync(request.ClientId);
if (client != null)
{
var resources = await _resourceStore.FindEnabledResourcesByScopeAsync(request.ScopesRequested);
if (resources != null && (resources.IdentityResources.Any() || resources.ApiResources.Any()))
{
return CreateConsentViewModel(model, returnUrl, request, client, resources);
}
else
{
_logger.LogError("No scopes matching: {0}", request.ScopesRequested.Aggregate((x, y) => x + ", " + y));
}
}
else
{
_logger.LogError("Invalid client id: {0}", request.ClientId);
}
}
else
{
_logger.LogError("No consent request matching request: {0}", returnUrl);
}
return null;
}
private ConsentViewModel CreateConsentViewModel(
ConsentInputModel model, string returnUrl,
AuthorizationRequest request,
Client client, Resources resources)
{
var vm = new ConsentViewModel();
vm.RememberConsent = model?.RememberConsent ?? true;
vm.ScopesConsented = model?.ScopesConsented ?? Enumerable.Empty<string>();
vm.ReturnUrl = returnUrl;
vm.ClientName = client.ClientName ?? client.ClientId;
vm.ClientUrl = client.ClientUri;
vm.ClientLogoUrl = client.LogoUri;
vm.AllowRememberConsent = client.AllowRememberConsent;
vm.IdentityScopes = resources.IdentityResources.Select(x => CreateScopeViewModel(x, vm.ScopesConsented.Contains(x.Name) || model == null)).ToArray();
vm.ResourceScopes = resources.ApiResources.SelectMany(x => x.Scopes).Select(x => CreateScopeViewModel(x, vm.ScopesConsented.Contains(x.Name) || model == null)).ToArray();
if (ConsentOptions.EnableOfflineAccess && resources.OfflineAccess)
{
vm.ResourceScopes = vm.ResourceScopes.Union(new ScopeViewModel[] {
GetOfflineAccessScope(vm.ScopesConsented.Contains(IdentityServer4.IdentityServerConstants.StandardScopes.OfflineAccess) || model == null)
});
}
return vm;
}
public 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 = ConsentOptions.OfflineAccessDisplayName,
Description = ConsentOptions.OfflineAccessDescription,
Emphasize = true,
Checked = check
};
}
}
}

@ -0,0 +1,19 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using System.Collections.Generic;
namespace IdentityServer4.Quickstart.UI
{
public class ConsentViewModel : ConsentInputModel
{
public string ClientName { get; set; }
public string ClientUrl { get; set; }
public string ClientLogoUrl { get; set; }
public bool AllowRememberConsent { get; set; }
public IEnumerable<ScopeViewModel> IdentityScopes { get; set; }
public IEnumerable<ScopeViewModel> ResourceScopes { get; set; }
}
}

@ -0,0 +1,18 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServer4.Quickstart.UI
{
public class ProcessConsentResult
{
public bool IsRedirect => RedirectUri != null;
public string RedirectUri { get; set; }
public bool ShowView => ViewModel != null;
public ConsentViewModel ViewModel { get; set; }
public bool HasValidationError => ValidationError != null;
public string ValidationError { get; set; }
}
}

@ -0,0 +1,16 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace IdentityServer4.Quickstart.UI
{
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; }
}
}

@ -0,0 +1,6 @@
namespace UserCenter
{
internal class ConsentService
{
}
}

@ -1,13 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Application.Domain.Entities;
using Application.Models;
using IdentityModel;
using IdentityServer4.Events;
using IdentityServer4.Services;
using Infrastructure.Data;
@ -19,12 +12,24 @@ using Infrastructure.Sms;
using Infrastructure.Web;
using Infrastructure.Web.DataAnnotations;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Localization;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace UserCenter.Controllers
{
@ -40,7 +45,6 @@ namespace UserCenter.Controllers
private readonly ISmsSender _smsSender;
private readonly IEventService _events;
public AccountController(IConfiguration cfg,
IRepository<User> userRepo,
IRepository<Site> siteRepo,
@ -48,7 +52,8 @@ namespace UserCenter.Controllers
IStringLocalizer<Resource> localizer,
IEmailSender emaliSender,
ISmsSender smsSender,
IEventService events)
IEventService events
)
{
this._cfg = cfg;
this._userRepo = userRepo;
@ -103,7 +108,7 @@ namespace UserCenter.Controllers
[HttpGet]
public IActionResult Login(string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
ViewData["ReturnUrl"] = returnUrl;
return View();
}
@ -168,14 +173,13 @@ namespace UserCenter.Controllers
if (success)
{
this._events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id.ToString(), user.UserName));
var userPermissions = this._userRepo.ReadOnlyTable().Where(o => o.UserName == userName)
var roles = this._userRepo.ReadOnlyTable().Where(o => o.UserName == userName)
.SelectMany(o => o.UserRoles)
.Select(o => o.Role)
.SelectMany(o => o.RolePermissions)
.Select(o => o.Permission.Number)
.ToList();
HttpContext.SignIn(model.UserName, userPermissions, model.RememberMe);
Microsoft.AspNetCore.Http.AuthenticationManagerExtensions.SignInAsync(HttpContext, user.Id.ToString(), user.UserName, new AuthenticationProperties { IsPersistent = model.RememberMe }, roles.Select(o => new Claim("role", o)).ToArray());
if (string.IsNullOrEmpty(returnUrl))
{
returnUrl = Url.Action("Index", "Home");
@ -229,6 +233,51 @@ namespace UserCenter.Controllers
return Challenge(new AuthenticationProperties { RedirectUri = "/" }, provider);
}
[AllowAnonymous]
public IActionResult Callback()
{
return Content(Request.QueryString.Value);
}
[AllowAnonymous]
public IActionResult GetToken(LoginModel model)
{
var user = this._userRepo.ReadOnlyTable().FirstOrDefault();
if (user == null) return Unauthorized();
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(this._cfg["jwt:key"]);
var authTime = DateTime.UtcNow;
var expiresAt = authTime.AddDays(7);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(JwtClaimTypes.Issuer,"server"),
new Claim(JwtClaimTypes.Audience,"client"),
new Claim(JwtClaimTypes.Id, user.Id.ToString()),
new Claim(JwtClaimTypes.Name, user.UserName),
new Claim(JwtClaimTypes.Email, user.Email),
new Claim(JwtClaimTypes.PhoneNumber, user.PhoneNumber)
}),
Expires = expiresAt,
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
return Ok(new
{
access_token = tokenString,
token_type = "Bearer",
profile = new
{
sid = user.Id,
name = user.UserName,
auth_time = new DateTimeOffset(authTime).ToUnixTimeSeconds(),
expires_at = new DateTimeOffset(expiresAt).ToUnixTimeSeconds()
}
});
}
#endregion 登录
#region 注册

@ -0,0 +1,19 @@
using System.Threading.Tasks;
using IdentityServer4.Models;
using IdentityServer4.Services;
namespace UserCenter
{
public class ProfileService : IProfileService
{
public Task GetProfileDataAsync(ProfileDataRequestContext context)
{
return Task.CompletedTask;
}
public Task IsActiveAsync(IsActiveContext context)
{
return Task.CompletedTask;
}
}
}

@ -18,6 +18,7 @@ namespace UserCenter
new EFConfigurationValue { Id = "server.urls", Value= "http://*:80" },
new EFConfigurationValue { Id = "security:key", Value= "111111111111111111111111"},
new EFConfigurationValue { Id = "security:iv", Value= "11111111"},
new EFConfigurationValue { Id = "jwt:key", Value= "111111111111111111111111"},
new EFConfigurationValue { Id = "email:host", Value= "nbaxp.com"},
new EFConfigurationValue { Id = "email:port", Value= "25"},
new EFConfigurationValue { Id = "email:user", Value= "admin@nbaxp.com"},

@ -28,89 +28,89 @@ namespace UserCenter
public Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
var userName = context.UserName;
var password = context.Password;
try
{
var user = this._userRepo.Table().FirstOrDefault(o => o.UserName == userName);
if (user == null)
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "invalid_credential", new Dictionary<string, object> { { "message", "用户不存在" } });
}
else
{
var maxAccessFailedCount = this._cfg.GetValue<int>("MaxFailedAccessAttemptsBeforeLockout");
var lockoutEndMinutes = this._cfg.GetValue<int>("DefaultAccountLockoutMinutes");
//var userName = context.UserName;
//var password = context.Password;
//try
//{
// var user = this._userRepo.Table().FirstOrDefault(o => o.UserName == userName);
// if (user == null)
// {
// context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "invalid_credential", new Dictionary<string, object> { { "message", "用户不存在" } });
// }
// else
// {
// var maxAccessFailedCount = this._cfg.GetValue<int>("MaxFailedAccessAttemptsBeforeLockout");
// var lockoutEndMinutes = this._cfg.GetValue<int>("DefaultAccountLockoutMinutes");
if (user.LockoutEnabled)//对已启用登录锁定的用户,如果当前登录时间超出锁定时间,先解除锁定状态
{
if (user.LockoutEnd.HasValue && DateTime.UtcNow > user.LockoutEnd)
{
user.LockoutEnd = null;
user.AccessFailedCount = 0;
this._userRepo.SaveChanges();
}
}
var success = false;
if (user.LockoutEnabled)//对启用登录锁定的用户进行验证
{
if (user.LockoutEnd.HasValue == false)
{
if (user.PasswordHash == this._encryptionService.CreatePasswordHash(password, user.SecurityStamp))
{
user.LockoutEnd = null;
user.AccessFailedCount = 0;
success = true;
}
else
{
user.AccessFailedCount += 1;
if (user.AccessFailedCount >= maxAccessFailedCount)
{
user.LockoutEnd = DateTime.UtcNow.AddMinutes(lockoutEndMinutes);
}
}
this._userRepo.SaveChanges();
}
}
else//对未启用登录锁定的用户进行验证
{
if (user.PasswordHash == this._encryptionService.CreatePasswordHash(password, user.SecurityStamp))
{
success = true;
}
}
if (success)
{
var roles = this._userRepo.ReadOnlyTable().Where(o => o.UserName == userName)
.SelectMany(o => o.UserRoles)
.Select(o => o.Role)
.SelectMany(o => o.RolePermissions)
.Select(o => o.Permission.Number)
.ToList();
var claims = new List<Claim> { new Claim("Name", userName) };
claims.AddRange(roles.Select(o => new Claim("Role", o)).ToList());
var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme, "Name", "Role"));
// if (user.LockoutEnabled)//对已启用登录锁定的用户,如果当前登录时间超出锁定时间,先解除锁定状态
// {
// if (user.LockoutEnd.HasValue && DateTime.UtcNow > user.LockoutEnd)
// {
// user.LockoutEnd = null;
// user.AccessFailedCount = 0;
// this._userRepo.SaveChanges();
// }
// }
// var success = false;
// if (user.LockoutEnabled)//对启用登录锁定的用户进行验证
// {
// if (user.LockoutEnd.HasValue == false)
// {
// if (user.PasswordHash == this._encryptionService.CreatePasswordHash(password, user.SecurityStamp))
// {
// user.LockoutEnd = null;
// user.AccessFailedCount = 0;
// success = true;
// }
// else
// {
// user.AccessFailedCount += 1;
// if (user.AccessFailedCount >= maxAccessFailedCount)
// {
// user.LockoutEnd = DateTime.UtcNow.AddMinutes(lockoutEndMinutes);
// }
// }
// this._userRepo.SaveChanges();
// }
// }
// else//对未启用登录锁定的用户进行验证
// {
// if (user.PasswordHash == this._encryptionService.CreatePasswordHash(password, user.SecurityStamp))
// {
// success = true;
// }
// }
// if (success)
// {
// var roles = this._userRepo.ReadOnlyTable().Where(o => o.UserName == userName)
// .SelectMany(o => o.UserRoles)
// .Select(o => o.Role)
// .SelectMany(o => o.RolePermissions)
// .Select(o => o.Permission.Number)
// .ToList();
// var claims = new List<Claim> { new Claim("Name", userName) };
// claims.AddRange(roles.Select(o => new Claim("Role", o)).ToList());
// var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme, "Name", "Role"));
context.Result = new GrantValidationResult(claimsPrincipal);
}
else
{
if (user.LockoutEnabled && user.LockoutEnd.HasValue)
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, $"用户被锁定,请于{user.LockoutEnd.Value.ToLocalTime().ToString("HH:mm")}后重试");
}
else
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "密码错误");
}
}
}
}
catch (Exception ex)
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, ex.Message);
}
// context.Result = new GrantValidationResult(claimsPrincipal);
// }
// else
// {
// if (user.LockoutEnabled && user.LockoutEnd.HasValue)
// {
// context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, $"用户被锁定,请于{user.LockoutEnd.Value.ToLocalTime().ToString("HH:mm")}后重试");
// }
// else
// {
// context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "密码错误");
// }
// }
// }
//}
//catch (Exception ex)
//{
// context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, ex.Message);
//}
return Task.CompletedTask;
}

@ -0,0 +1,43 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace IdentityServer4.Quickstart.UI
{
public class SecurityHeadersAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext context)
{
var result = context.Result;
if (result is ViewResult)
{
if (!context.HttpContext.Response.Headers.ContainsKey("X-Content-Type-Options"))
{
context.HttpContext.Response.Headers.Add("X-Content-Type-Options", "nosniff");
}
if (!context.HttpContext.Response.Headers.ContainsKey("X-Frame-Options"))
{
context.HttpContext.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
}
var csp = "default-src 'self';";
// an example if you need client images to be displayed from twitter
//var csp = "default-src 'self'; img-src 'self' https://pbs.twimg.com";
// once for standards compliant browsers
if (!context.HttpContext.Response.Headers.ContainsKey("Content-Security-Policy"))
{
context.HttpContext.Response.Headers.Add("Content-Security-Policy", csp);
}
// and once again for IE
if (!context.HttpContext.Response.Headers.ContainsKey("X-Content-Security-Policy"))
{
context.HttpContext.Response.Headers.Add("X-Content-Security-Policy", csp);
}
}
}
}
}

@ -1,4 +1,5 @@
using Application.Domain.Entities;
using IdentityModel;
using IdentityServer4;
using IdentityServer4.Models;
using Infrastructure.Data;
@ -10,14 +11,17 @@ using Infrastructure.Sms;
using Infrastructure.Web;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace UserCenter
@ -38,16 +42,19 @@ namespace UserCenter
public override void AddAuthentication(IServiceCollection services)
{
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryIdentityResources(new IdentityResource[] {
new IdentityResources.OpenId(),
new IdentityResources.Profile()
})
.AddInMemoryApiResources(new ApiResource[] { new ApiResource("api1", "My API") })
.AddInMemoryClients(new IdentityServer4.Models.Client[] {
new IdentityServer4.Models.Client
{
ClientId="mvc",
ClientName="物联网平台",
AllowedGrantTypes = GrantTypes.Implicit,
RequireConsent=false,
RedirectUris = { "http://localhost:8082/signin-oidc" },
PostLogoutRedirectUris = { "http://localhost:8082/signout-callback-oidc" },
@ -57,8 +64,49 @@ namespace UserCenter
IdentityServerConstants.StandardScopes.Profile
}
}
});
//.AddResourceOwnerValidator<ResourceOwnerValidator>();
})
.AddResourceOwnerValidator<ResourceOwnerValidator>()
//.AddProfileService<ProfileService>()
;
services.AddAuthentication(o =>
{
o.DefaultAuthenticateScheme = IdentityServerConstants.DefaultCookieAuthenticationScheme;
o.DefaultSignOutScheme = IdentityServerConstants.SignoutScheme;
})
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, o =>
{
o.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = JwtClaimTypes.Name,
RoleClaimType = JwtClaimTypes.Role,
ValidIssuer = "server",
ValidAudience = "client",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(this._cfg["jwt:key"]))
};
o.Events = new JwtBearerEvents()
{
OnChallenge = context =>
{
//context.Token = context.Request.Query["access_token"];
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
//context.Token = context.Request.Query["access_token"];
return Task.CompletedTask;
},
OnTokenValidated = context =>
{
//context.Token = context.Request.Query["access_token"];
return Task.CompletedTask;
},
OnMessageReceived = context =>
{
//context.Token = context.Request.Query["access_token"];
return Task.CompletedTask;
}
};
});
//services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
// .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, opts =>
// {
@ -83,12 +131,12 @@ namespace UserCenter
// options.ClientId = "6ec6712a4dbbe3f1f1ac";
// options.ClientSecret = "ea91f08553a3b242340a905fb000d5a828d9a69e";
// })
// .AddQQ(o =>
// {
// //https://connect.qq.com/manage.html
// o.ClientId = "101569040";
// o.ClientSecret = "5541d994fe8f3b3fa428c63a47139b39";
// });
//.AddQQ(o =>
//{
// //https://connect.qq.com/manage.html
// o.ClientId = "101569040";
// o.ClientSecret = "5541d994fe8f3b3fa428c63a47139b39";
//});
}
public override void UseAuthentication(IApplicationBuilder app)

@ -0,0 +1,82 @@
@model ConsentViewModel
<div class="page-consent">
<div class="row page-header">
<div class="col-sm-10">
@if (Model.ClientLogoUrl != null)
{
<div class="client-logo"><img src="@Model.ClientLogoUrl"></div>
}
<h1>
@Model.ClientName
<small>is requesting your permission</small>
</h1>
</div>
</div>
<div class="row">
<div class="col-sm-8">
@Html.Partial("_ValidationSummary")
<form asp-action="Index" class="consent-form">
<input type="hidden" asp-for="ReturnUrl" />
<div>Uncheck the permissions you do not wish to grant.</div>
@if (Model.IdentityScopes.Any())
{
<div class="panel panel-default consent-buttons">
<div class="panel-heading">
<span class="glyphicon glyphicon-user"></span>
Personal Information
</div>
<ul class="list-group">
@foreach (var scope in Model.IdentityScopes)
{
@Html.Partial("_ScopeListItem", scope)
}
</ul>
</div>
}
@if (Model.ResourceScopes.Any())
{
<div class="panel panel-default">
<div class="panel-heading">
<span class="glyphicon glyphicon-tasks"></span>
Application Access
</div>
<ul class="list-group">
@foreach (var scope in Model.ResourceScopes)
{
@Html.Partial("_ScopeListItem", scope)
}
</ul>
</div>
}
@if (Model.AllowRememberConsent)
{
<div class="consent-remember">
<label>
<input class="consent-scopecheck" asp-for="RememberConsent" />
<strong>Remember My Decision</strong>
</label>
</div>
}
<div class="consent-buttons">
<button name="button" value="yes" class="btn btn-primary" autofocus>Yes, Allow</button>
<button name="button" value="no" class="btn">No, Do Not Allow</button>
@if (Model.ClientUrl != null)
{
<a class="pull-right btn btn-default" target="_blank" href="@Model.ClientUrl">
<span class="glyphicon glyphicon-info-sign"></span>
<strong>@Model.ClientName</strong>
</a>
}
</div>
</form>
</div>
</div>
</div>

@ -0,0 +1,34 @@
@model ScopeViewModel
<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>

@ -8,4 +8,5 @@
@using Infrastructure.Data
@using Application.Domain.Entities
@using Application.Models
@using IdentityServer4.Quickstart.UI
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@ -0,0 +1 @@
{"KeyId":"dc1a31fd2267d34de72cdda702f5990e","Parameters":{"D":"GxaAh43zyM+h6qg8+CbXyHEJ8C4HE54IWFsCACNchA5rDO5V4j1NKQ+SgOAjxZv9/j4sGIC/lUAKfyExc1g1I/UQ+EA/+/VADz1kxIINVsvGsCCpd4BYQtqunaFnjzNgR0k6drZPL3hvxTculaN74/WhhJeHKo0fpzqjZwMCM0xBBX+2YQbzGnb0mn+uiYk4bIgL4khM/fGqcx4tX61NvA2VZuliN622GAcvwvfzXu7WAK+C7Mp2A8OF3EqqDxbu5x8yUohGmC0KmihANaZlPDSdNqNijXvEZjB47Hpn6ZkT52Uhkcg61zKNwXQaW1UZZ85mtInn4sDM/PZ0us/yHQ==","DP":"VTaHh33hEANGH6sCQSnIWRuGiAppU0O0DJUO5vYfOgXnx9t0SKbjkirm5Irg8CDzSpdBhIeuJ631xOGehpSlsUeUqEwkn1BxSsa0bcZgq/qkSv2DR8Ykmc6zsEeKi35N2fGleoV/FBMD+sbaJZP7nYAZV9oRD86Qjha4P09rStk=","DQ":"nJGjcaY+YZ6n9zpZKxJ7NvziFKSw8YC+oRX34q+XxSDquV6t+hbHmhNzZ0C8C81jz+2BTvNuF62miNIcIBhXnVcbPmXC5LE95hy820y4UBgq0dudhDkyrZaQZ6y2Zyw4gkwYnQPC0DWGpHVg/7gFJmLnuWappiv35FBWll3w99c=","Exponent":"AQAB","InverseQ":"EiCsy4Le5yrL2o4JWo3iomzBahMSrPLPQFXIlYrPBmemGmJ/HXSMwsXWlhVq86mgzfQLZG5XIaUx5imDu16Zfg2h6N9BglaHRSuHv5VO/s27n7zzkBZctBW2YU0gpNjdIO4SQjZ0TGztdOP4a5VJJ3JNRtj3vuGpV8wU4JfPy5o=","Modulus":"ogVFdnGUovlbtfCGNlcle4uEAxVQYy7YFHOpENSg0xe9iZOcG9S3OrsizK8m8SiHAMZeaBVPXiAAunAdQ619TihZGDXWFvjrzTGaIWIOLa3u8SYM8o+u9Gj8VtJB8pBsqIlr6s2x3Y1znt/ep8FriCGV1sN1RBzt8qR/a14Rk7N4VfqGowfoQjlV6joVubZpLTzUYjcnD8v2gPg7huI2WeeoN7ZrZiLHaE2r7+rMR/6o8/8qi4g6N8ShbKO9Fvib2gFjPZ3HIEvGpvkUVXawcEABUzA2YwUnqce3yH/qfUrvtjx0wHUuN1R9nOM1qZporytyXqDYOpRh7AJiUUjUBQ==","P":"xNXHdlJwXwh2/ErxtYrucwYYpZkmfTZP6Pu8i1wy0ZiTqv8ik7d+S5ANa9KS2VzSvJEy4z7cOiUm0w9eq8EFpdFZwm81H1Zfmbcoycd3ThjC8ntYub3rSGTj8ofgH0NlT/BnMDWlo9cSfsfG8Usws44C4wyIOlI4fWB1bOLltZ8=","Q":"0riPTtHbi7dFABScQHj9syaL1uHToVDiBxmydaSnLuSHwNYyS2cmcKLVjTxauKbBvDhtShKgZJRkJwMMhLyQb1yxaEWHNnBsYRqktWyYobbjMiPsrHNr7fFXxTrwZAbqtKwts5f4J/TkBrq2W4MtYz2e0ReIE6ukoZDeBA0Da9s="}}
Loading…
Cancel
Save