恢复jsonp单点登录,为发布新版本做准备

将api网关和消息服务合并到用户中心
TangShanKaiPing
wanggang 6 years ago
parent 93c287bab1
commit 079f8fc9d3

@ -1,16 +0,0 @@
*.bak
*.suo
*.db
*.user
.vs
obj
Obj
bin
Bin
debug
Debug
release
Release
Logs
logs
node_modules

@ -1,19 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.2.3" />
<PackageReference Include="Ocelot" Version="13.5.0" />
<PackageReference Include="RavenDB.Embedded" Version="4.1.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Infrastructure\Infrastructure.csproj" />
</ItemGroup>
</Project>

@ -1,36 +0,0 @@
using System;
using Infrastructure.Web.SignalR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
namespace ApiGateway.Controllers
{
public class HomeController : Controller
{
private readonly IHubContext<PageHub> _pageHubContext;
public HomeController(IHubContext<PageHub> pageHubContext)
{
this._pageHubContext = pageHubContext;
}
public IActionResult Index()
{
return View();
}
public IActionResult Test(string id = "id1", string name = "智慧教室", string message = "节点数据信息节点数据信息节点数据信息节点数据信息节点数据信息节点数据信息节点数据信息")
{
this._pageHubContext.Clients.All.SendAsync("receive", new
{
groupId = id,
groupName = name,
user = "管理员",
message = message,
timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds(),
read = false
});
return Content("");
}
}
}

@ -1,11 +0,0 @@
using System;
namespace ApiGateway.Models
{
public class ErrorViewModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
}

@ -1,33 +0,0 @@
using System.Collections.Generic;
using Infrastructure.Application;
using Infrastructure.Configuration;
using Infrastructure.Extensions;
using Infrastructure.Web.Hosting;
using Microsoft.AspNetCore;
namespace ApiGateway
{
public class Program
{
public static void Main(string[] args)
{
var host = Helper.Instance.GetLocalIP().ToString();
WebHost.CreateDefaultBuilder(args)
.Run<Startup>(new List<EFConfigurationValue> {
new EFConfigurationValue { Id = "openapi.title", Value= "web api" },
new EFConfigurationValue { Id = "openapi.version", Value= "1.0" },
new EFConfigurationValue { Id = "server.urls", Value= "https://*:44380;http://*:8080" },
new EFConfigurationValue { Id = "security:key", Value= "111111111111111111111111"},
new EFConfigurationValue { Id = "security:iv", Value= "11111111"},
new EFConfigurationValue { Id = "usercenter:key", Value= "123456"},
new EFConfigurationValue { Id = "usercenter:login", Value= $"http://{host}:8000/Account/Login"},
new EFConfigurationValue { Id = "usercenter:logout", Value= $"http://{host}:8000/Account/Logout"},
new EFConfigurationValue { Id = "usercenter:register", Value= $"http://{host}:8000/Account/Register"},
//
new EFConfigurationValue { Id = "name", Value= "网关"},
new EFConfigurationValue { Id = "logo", Value= "/images/logo.png",Type= InputType.ImageUrl},
new EFConfigurationValue { Id = "copyright", Value= "Copyright © {now} Company. All rights reserved",Type= InputType.Html}
});
}
}
}

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:8080",
"sslPort": 44380
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"ApiGateway": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:44380;http://localhost:8080",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

@ -1,390 +0,0 @@
using System;
using System.Threading.Tasks;
//using Application.Domain.Entities;
using Infrastructure.Email;
using Infrastructure.Sms;
using Infrastructure.Web;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using Raven.Embedded;
namespace ApiGateway
{
public class Startup : BaseStartup
{
public Startup(IConfiguration configuration, IHostingEnvironment env) : base(configuration, env)
{
EmbeddedServer.Instance.StartServer();
}
public override void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IEmailSender, EmptyEmailSender>();
services.AddTransient<ISmsSender, EmptySmsSender>();
services.AddSignalR(o => o.EnableDetailedErrors = true);
base.ConfigureServices(services);
services.AddOcelot();
}
public override void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
base.Configure(app, env, loggerFactory);
app.UseOcelot().Wait();
}
public override Task ValidatePrincipal(CookieValidatePrincipalContext arg)
{
return Task.Run(() =>
{
//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);
//}
});
}
public override void OnModelCreating(ModelBuilder modelBuilder)
{
//modelBuilder.Entity<PermissionCategory>().HasOne(o => o.Parent).WithMany(o => o.Children).HasForeignKey(o => o.ParentId);
//modelBuilder.Entity<Permission>().HasOne(o => o.Category).WithMany(o => o.Permissions).HasForeignKey(o => o.CategoryId);
//modelBuilder.Entity<UserRole>().HasOne(o => o.User).WithMany(o => o.UserRoles).HasForeignKey(o => o.UserId);
//modelBuilder.Entity<UserRole>().HasOne(o => o.Role).WithMany(o => o.UserRoles).HasForeignKey(o => o.RoleId);
//modelBuilder.Entity<RolePermission>().HasOne(o => o.Role).WithMany(o => o.RolePermissions).HasForeignKey(o => o.RoleId);
//modelBuilder.Entity<RolePermission>().HasOne(o => o.Permission).WithMany(o => o.RolePermissions).HasForeignKey(o => o.PermissionId);
//modelBuilder.Entity<User>().HasIndex(o => o.UserName).IsUnique();
//modelBuilder.Entity<Role>().HasIndex(o => o.Name).IsUnique();
//modelBuilder.Entity<PermissionCategory>().HasIndex(o => o.Number).IsUnique();
//modelBuilder.Entity<Permission>().HasIndex(o => o.Number).IsUnique();
//modelBuilder.Entity<UserRole>().HasIndex(o => new { o.UserId, o.RoleId }).IsUnique();
//modelBuilder.Entity<RolePermission>().HasIndex(o => new { o.RoleId, o.PermissionId }).IsUnique();
////学校课程
////专业分类用来组织学校、学院、系等
//modelBuilder.Entity<MajorCategory>().HasOne(o => o.Parent).WithMany(o => o.Children).HasForeignKey(o => o.ParentId);
//modelBuilder.Entity<MajorCategory>().HasIndex(o => new { o.ParentId, o.Number }).IsUnique();
////专业用来组织不同学制如3年专科、4年本科
//modelBuilder.Entity<Major>().HasOne(o => o.Category).WithMany(o => o.Majors).HasForeignKey(o => o.CategoryId);
////每批次入学的学生,按照学制、就业方向等制定不同的教学计划
//modelBuilder.Entity<TeachingPlan>().HasOne(o => o.Major).WithMany(o => o.Plans).HasForeignKey(o => o.MajorId);
////每个教学计划包含不同个学期和就业方向
//modelBuilder.Entity<Semester>().HasOne(o => o.Plan).WithMany(o => o.Semesters).HasForeignKey(o => o.PlanId);
////每个学期包含多个学期课程
//modelBuilder.Entity<SemesterCourse>().HasOne(o => o.Semester).WithMany(o => o.Courses).HasForeignKey(o => o.SemesterId);
////一个课程期对应多个教学计划学期中的课程,这样将学校的学期课程和课程的期统一起来
//modelBuilder.Entity<SemesterCourse>().HasOne(o => o.Term).WithMany(o => o.SemesterCourses).HasForeignKey(o => o.TermId);
////课程分类
//modelBuilder.Entity<CourseCategory>().HasOne(o => o.Parent).WithMany(o => o.Children).HasForeignKey(o => o.ParentId);
//modelBuilder.Entity<CourseCategory>().HasIndex(o => new { o.ParentId, o.Number }).IsUnique();
////课程分类
//modelBuilder.Entity<BookCategory>().HasOne(o => o.Parent).WithMany(o => o.Children).HasForeignKey(o => o.ParentId);
//modelBuilder.Entity<BookCategory>().HasIndex(o => new { o.ParentId, o.Number }).IsUnique();
//modelBuilder.Entity<Book>().HasOne(o => o.BookCategory).WithMany(o => o.Books).HasForeignKey(o => o.BookCategoryId);
//modelBuilder.Entity<Section>().HasOne(o => o.Parent).WithMany(o => o.Children).HasForeignKey(o => o.ParentId);
//modelBuilder.Entity<Section>().HasIndex(o => new { o.ParentId, o.Number }).IsUnique();
////每本书有多个章节
//modelBuilder.Entity<Section>().HasOne(o => o.Book).WithMany(o => o.Sections).HasForeignKey(o => o.BookId);
////课程
//modelBuilder.Entity<Course>().HasOne(o => o.Category).WithMany(o => o.Courses).HasForeignKey(o => o.CategoryId);
////每个课程有多个期
//modelBuilder.Entity<Term>().HasOne(o => o.Course).WithMany(o => o.Terms).HasForeignKey(o => o.CourseId);
//modelBuilder.Entity<Term>().HasOne(o => o.Book).WithMany(o => o.Terms).HasForeignKey(o => o.BookId);
////每期有多个课时
//modelBuilder.Entity<Lesson>().HasOne(o => o.Term).WithMany(o => o.Lessons).HasForeignKey(o => o.TermId);
////课时和资源多对多多对多
//modelBuilder.Entity<LessonResource>().HasOne(o => o.Lesson).WithMany(o => o.LessonResources).HasForeignKey(o => o.LessionId);
//modelBuilder.Entity<LessonResource>().HasOne(o => o.Resource).WithMany(o => o.LessonResources).HasForeignKey(o => o.ResourceId);
//modelBuilder.Entity<LessonResource>().HasIndex(o => new { o.LessionId, o.ResourceId }).IsUnique();
////学生和课程的期多对多
//modelBuilder.Entity<TermUser>().HasOne(o => o.Term).WithMany(o => o.TermUsers).HasForeignKey(o => o.TermId);
//modelBuilder.Entity<TermUser>().HasOne(o => o.User).WithMany(o => o.TermUsers).HasForeignKey(o => o.UserId);
//modelBuilder.Entity<TermUser>().HasIndex(o => new { o.TermId, o.UserId }).IsUnique();
//modelBuilder.Entity<ResourceCategory>().HasOne(o => o.Parent).WithMany(o => o.Children).HasForeignKey(o => o.ParentId);
//modelBuilder.Entity<Resource>().HasOne(o => o.User).WithMany(o => o.Resources).HasForeignKey(o => o.UserId);
//modelBuilder.Entity<Resource>().HasOne(o => o.Category).WithMany(o => o.Resources).HasForeignKey(o => o.CategoryId);
//modelBuilder.Entity<Resource>().HasOne(o => o.Course).WithMany(o => o.Resources).HasForeignKey(o => o.CourseId);
//modelBuilder.Entity<Resource>().HasOne(o => o.Section).WithMany(o => o.Resources).HasForeignKey(o => o.SectionId);
//modelBuilder.Entity<Resource>().Property(o => o.Name).IsRequired().HasMaxLength(255);
////习题
//modelBuilder.Entity<Question>().HasOne(o => o.User).WithMany(o => o.Questions).HasForeignKey(o => o.UserId);
//modelBuilder.Entity<Question>().HasOne(o => o.Course).WithMany(o => o.Questions).HasForeignKey(o => o.CourseId);
//modelBuilder.Entity<Question>().HasOne(o => o.Section).WithMany(o => o.Questions).HasForeignKey(o => o.SectionId);
////习题答题记录
//modelBuilder.Entity<UserQuestion>().HasOne(o => o.User).WithMany(o => o.UserQuestions).HasForeignKey(o => o.UserId);
//modelBuilder.Entity<UserQuestion>().HasOne(o => o.Question).WithMany(o => o.UserQuestions).HasForeignKey(o => o.QuestionId);
//modelBuilder.Entity<UserQuestion>().HasIndex(o => new { o.UserId, o.QuestionId }).IsUnique();
////试题答题记录
//modelBuilder.Entity<UserPaperQuestion>().HasOne(o => o.User).WithMany(o => o.UserPaperQuestions).HasForeignKey(o => o.UserId);
//modelBuilder.Entity<UserPaperQuestion>().HasOne(o => o.PaperQuestion).WithMany(o => o.UserPaperQuestions).HasForeignKey(o => o.PaperQuestionId);
//modelBuilder.Entity<UserPaperQuestion>().HasIndex(o => new { o.UserId, o.PaperQuestionId }).IsUnique();
////试卷答题记录
//modelBuilder.Entity<UserPaper>().HasOne(o => o.User).WithMany(o => o.UserPapers).HasForeignKey(o => o.UserId);
//modelBuilder.Entity<UserPaper>().HasOne(o => o.Paper).WithMany(o => o.UserPapers).HasForeignKey(o => o.PaperId);
//modelBuilder.Entity<UserPaper>().HasIndex(o => new { o.UserId, o.PaperId }).IsUnique();
////考题是具有习题的属性和分值等其他和试卷相关的属性
//modelBuilder.Entity<PaperQuestion>().HasOne(o => o.Paper).WithMany(o => o.Questions).HasForeignKey(o => o.PaperId);
}
public override void Seed(DbContext dbContext, IServiceProvider serviceProvider, IConfiguration configuration)
{
//dbContext.Set<PermissionCategory>().Add(new PermissionCategory
//{
// Name = "配置",
// Number = "Configuration",
// Permissions = new List<Permission> {
// new Permission { Name = "查询配置", Number = "ListConfiguration",DisplayOrder =1 },
// new Permission { Name = "修改配置", Number = "EditConfiguration",DisplayOrder =2 }
// }
//});
//int i = 1;
//var skipReadCollection = new string[] { "Permission" };
//var skipAddCollection = new string[] { "Permission", "Setting", "Node", "Device", "Data", "Api", "Parameter" };
//foreach (var item in dbContext.Model.GetEntityTypes())
//{
// var type = item.ClrType;
// var name = type.GetDisplayName();
// var number = type.Name;
// var category = new PermissionCategory
// {
// Name = name,
// Number = type.Name,
// DisplayOrder = i
// };
// category.Permissions.Add(new Permission { Name = $"查询{name}", Number = $"List{number}", DisplayOrder = 10 * i + 1 });
// if (!skipReadCollection.Contains(type.Name))
// {
// category.Permissions.Add(new Permission { Name = $"查看{name}", Number = $"Read{number}", DisplayOrder = 10 * i + 2 });
// }
// if (!skipAddCollection.Contains(type.Name))
// {
// category.Permissions.Add(new Permission { Name = $"添加{name}", Number = $"Add{number}", DisplayOrder = 10 * i + 3 });
// }
// if (!typeof(IDisableUpdate).IsAssignableFrom(type))
// {
// category.Permissions.Add(new Permission { Name = $"修改{name}", Number = $"Edit{number}", DisplayOrder = 10 * i + 4 });
// }
// if (!typeof(IDisableDelete).IsAssignableFrom(type))
// {
// category.Permissions.Add(new Permission { Name = $"删除{name}", Number = $"Delete{number}", DisplayOrder = 10 * i + 5 });
// }
// dbContext.Set<PermissionCategory>().Add(category);
// i += 1;
//}
//dbContext.SaveChanges();
//var adminRole = new Role { Name = "管理员", IsReadOnly = true };
//foreach (var item in dbContext.Set<Permission>())
//{
// adminRole.RolePermissions.Add(new RolePermission { Permission = item, IsReadOnly = true });
//}
//var user1Id = dbContext.Set<User>().Add(new User
//{
// UserName = "admin",
// UserRoles = new List<UserRole> { new UserRole { Role = adminRole } }
//}).Entity.Id;
//dbContext.SaveChanges();
////课程分类
//dbContext.Set<CourseCategory>().Add(new CourseCategory { Name = "高职高专", Number = "2", DisplayOrder = 2 });
//dbContext.Set<CourseCategory>().Add(new CourseCategory { Name = "大学大专", Number = "3", DisplayOrder = 3 });
//dbContext.Set<CourseCategory>().Add(new CourseCategory { Name = "大学", Number = "4", DisplayOrder = 4 });
//dbContext.Set<CourseCategory>().Add(new CourseCategory { Name = "研究生", Number = "5", DisplayOrder = 5 });
//dbContext.Set<CourseCategory>().Add(new CourseCategory { Name = "成人教育", Number = "6", DisplayOrder = 6 });
//dbContext.Set<CourseCategory>().Add(new CourseCategory { Name = "职业培训", Number = "7", DisplayOrder = 7 });
//dbContext.SaveChanges();
////教学计划
//var major1 =
//dbContext.Set<MajorCategory>().Add(new MajorCategory
//{
// Name = "计算机学院",
// Number = "0",
// Majors = new List<Major>
// {
// new Major{
// Name="计算机科学与技术",
// Plans = new List<TeachingPlan>
// {
// new TeachingPlan
// {
// Start=DateTime.Now.Date,
// Years=4,
// Degree="学士",
// Career="软件工程方向",
// Semesters = new List<Semester>
// {
// new Semester
// {
// Name="第1学期",
// Courses = new List<SemesterCourse>
// {
// new SemesterCourse
// {
// Name="计算机应用",
// Number ="106090100",
// Category="学科基础课",
// Type="必修课",
// Score=4
// }
// }
// }
// }
// }
// }
// }
// }
//});
//dbContext.SaveChanges();
////资源类型初始化
//var resourceTypeId1 = dbContext.Set<ResourceCategory>().Add(new ResourceCategory { Name = "文档", Number = "01", DisplayOrder = 01 }).Entity.Id;
//dbContext.Set<ResourceCategory>().Add(new ResourceCategory { Name = "音频", Number = "01", DisplayOrder = 01 });
//dbContext.Set<ResourceCategory>().Add(new ResourceCategory { Name = "视频", Number = "01", DisplayOrder = 01 });
//dbContext.Set<ResourceCategory>().Add(new ResourceCategory { Name = "动画", Number = "01", DisplayOrder = 01 });
//dbContext.Set<ResourceCategory>().Add(new ResourceCategory { Name = "虚拟仿真", Number = "01", DisplayOrder = 01 });
////资源分类初始化
//dbContext.SaveChanges();
//dbContext.Set<CourseCategory>().Add(new CourseCategory
//{
// Name = "中职中专",
// Number = "1",
// DisplayOrder = 1,
// Children = new List<CourseCategory> {
// new CourseCategory
// {
// Name="公开课",
// Number="1",
// DisplayOrder=1
// },
// new CourseCategory
// {
// Name="专业课",
// Number="2",
// DisplayOrder=2,
// Children=new List<CourseCategory>
// {
// new CourseCategory
// {
// Name = "信息技术类",
// Number = "10609",
// DisplayOrder = 106,
// Children = new List<CourseCategory>
// {
// new CourseCategory
// {
// Name="计算机应用",
// Number="106090100",
// DisplayOrder=106010100,
// Courses = new List<Course>
// {
// new Course
// {
// Name="Java基础",
// Number="10001",
// Image="/upload/1.jpg",
// Description="本课程是以Java语言来讲授程序设计的入门知识而非具体教授Java语言关于Java语言的全面知识还需要学习本课程的后续课程——“Java语言程序设计进阶”。",
// Terms = new List<Term>
// {
// new Term
// {
// Name="2018-2019学年下学期",
// Start= new DateTime(2018,9,1),
// End=new DateTime(2019,1,1),
// Lessons=new List<Lesson>
// {
// new Lesson
// {
// Name="导论",
// DisplayOrder=1
// },
// new Lesson
// {
// Name="基础",
// DisplayOrder=2
// }
// }
// }
// }
// }
// }
// }
// }
// }
// }
// }
// }
//});
//dbContext.SaveChanges();
//dbContext.Set<BookCategory>().Add(new BookCategory
//{
// Name = "理科教材",
// Number = "0000",
// Books = new List<Book>
// {
// new Book
// {
// Name="计算机应用基础",
// Number="ISBN 0000",
// Sections = new List<Section>
// {
// new Section
// {
// Name="导论上",
// Number="1.1"
// },
// new Section
// {
// Name="导论下",
// Number="1.2"
// }
// }
// }
// }
//});
//dbContext.SaveChanges();
//dbContext.Set<Resource>().Add(new Resource
//{
// CategoryId = dbContext.Set<ResourceCategory>().FirstOrDefault(o => o.Name == "视频").Id,
// Name = "导论",
// File = "/upload/1.mp4",
// UserId = user1Id,
// CourseId = dbContext.Set<Course>().FirstOrDefault(o => o.Name == "Java基础").Id,
// SectionId = dbContext.Set<Section>().FirstOrDefault(o => o.Name == "导论上").Id,
//});
//dbContext.SaveChanges();
//dbContext.Set<LessonResource>().Add(new LessonResource
//{
// Name = "视频",
// LessionId = dbContext.Set<Lesson>().FirstOrDefault(o => o.Name == "导论").Id,
// ResourceId = dbContext.Set<Resource>().FirstOrDefault(o => o.Name == "导论").Id,
//});
//dbContext.SaveChanges();
//foreach (var item in dbContext.Set<CourseCategory>())
//{
// item.UpdatePath();
//}
//dbContext.SaveChanges();
}
}
}

@ -1,8 +0,0 @@
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

@ -1,6 +0,0 @@
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>

@ -1,25 +0,0 @@
@model ErrorViewModel
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>

@ -1,25 +0,0 @@
@using Microsoft.AspNetCore.Http.Features
@{
var consentFeature = Context.Features.Get<ITrackingConsentFeature>();
var showBanner = !consentFeature?.CanTrack ?? false;
var cookieString = consentFeature?.CreateConsentCookie();
}
@if (showBanner)
{
<div id="cookieConsent" class="alert alert-info alert-dismissible fade show" role="alert">
Use this space to summarize your privacy and cookie use policy. <a asp-area="" asp-controller="Home" asp-action="Privacy">Learn More</a>.
<button type="button" class="accept-policy close" data-dismiss="alert" aria-label="Close" data-cookie-string="@cookieString">
<span aria-hidden="true">Accept</span>
</button>
</div>
<script>
(function () {
var button = document.querySelector("#cookieConsent button[data-cookie-string]");
button.addEventListener("click", function (event) {
document.cookie = button.dataset.cookieString;
}, false);
})();
</script>
}

@ -1,77 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - ApiGateway</title>
<environment include="Development">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
</environment>
<environment exclude="Development">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute"
crossorigin="anonymous"
integrity="sha256-eSi1q2PG6J7g7ib17yAaWMcrr5GrtohYChqibrV7PBE="/>
</environment>
<link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">ApiGateway</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<partial name="_CookieConsentPartial" />
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
&copy; 2019 - ApiGateway - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
</footer>
<environment include="Development">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
</environment>
<environment exclude="Development">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
asp-fallback-test="window.jQuery"
crossorigin="anonymous"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.bundle.min.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
crossorigin="anonymous"
integrity="sha256-E/V4cWE4qvAeO5MOhjtGtqDzPndRO1LBk8lJ/PR7CA4=">
</script>
</environment>
<script src="~/js/site.js" asp-append-version="true"></script>
@RenderSection("Scripts", required: false)
</body>
</html>

@ -1,18 +0,0 @@
<environment include="Development">
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
</environment>
<environment exclude="Development">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js"
asp-fallback-src="~/lib/jquery-validation/dist/jquery.validate.min.js"
asp-fallback-test="window.jQuery && window.jQuery.validator"
crossorigin="anonymous"
integrity="sha256-F6h55Qw6sweK+t7SiOJX+2bpSAa3b/fnlrVCJvmEj1A=">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js"
asp-fallback-src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive"
crossorigin="anonymous"
integrity="sha256-9GycpJnliUjJDVDqP0UEu/bsm9U+3dnQUH8+3W10vkY=">
</script>
</environment>

@ -1,3 +0,0 @@
@using ApiGateway
@using ApiGateway.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@ -1,3 +0,0 @@
@{
Layout = "_Layout";
}

@ -1,10 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"UseMiniProfiler": true
}

@ -1,54 +0,0 @@
{
"version": "1.0.0-beta.1",
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"UseMiniProfiler": false,
"ConnectionStrings": {
"database.mysql.connection": "Server=127.0.0.1;Port=3306;Database=apigeteway;Uid=root;Pwd=root;",
"database.sqlite.connection": "Data Source=apigeteway.db"
},
"AppSettings": {
"database": "sqlite",
"UseCookieSessionStore": false
},
"GlobalConfiguration": {
"BaseUrl": "http://192.168.3.8080/"
},
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/{version}/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "192.168.3.84",
"Port": 8000
}
],
"UpstreamPathTemplate": "/api/{version}/identity/{everything}",
"UpstreamHttpMethod": [],
"AuthenticationOptions": {
"AuthenticationProviderKey": "IdentityApiKey",
"AllowedScopes": []
}
},
{
"DownstreamPathTemplate": "/api/{version}/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "192.168.3.84",
"Port": 8001
}
],
"UpstreamPathTemplate": "/api/{version}/iot/{everything}",
"UpstreamHttpMethod": [],
"AuthenticationOptions": {
"AuthenticationProviderKey": "IdentityApiKey",
"AllowedScopes": []
}
}
]
}

@ -1,56 +0,0 @@
/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
for details on configuring this project to bundle and minify static web assets. */
a.navbar-brand {
white-space: normal;
text-align: center;
word-break: break-all;
}
/* Sticky footer styles
-------------------------------------------------- */
html {
font-size: 14px;
}
@media (min-width: 768px) {
html {
font-size: 16px;
}
}
.border-top {
border-top: 1px solid #e5e5e5;
}
.border-bottom {
border-bottom: 1px solid #e5e5e5;
}
.box-shadow {
box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
}
button.accept-policy {
font-size: 1rem;
line-height: inherit;
}
/* Sticky footer styles
-------------------------------------------------- */
html {
position: relative;
min-height: 100%;
}
body {
/* Margin bottom by footer height */
margin-bottom: 60px;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
white-space: nowrap;
/* Set the fixed height of the footer here */
height: 60px;
line-height: 60px; /* Vertically center the text there */
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

@ -1,4 +0,0 @@
// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
// for details on configuring this project to bundle and minify static web assets.
// Write your JavaScript code.

@ -1,22 +0,0 @@
The MIT License (MIT)
Copyright (c) 2011-2018 Twitter, Inc.
Copyright (c) 2011-2018 The Bootstrap Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,331 +0,0 @@
/*!
* Bootstrap Reboot v4.1.3 (https://getbootstrap.com/)
* Copyright 2011-2018 The Bootstrap Authors
* Copyright 2011-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
line-height: 1.15;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
-ms-overflow-style: scrollbar;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
@-ms-viewport {
width: device-width;
}
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
display: block;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #212529;
text-align: left;
background-color: #fff;
}
[tabindex="-1"]:focus {
outline: 0 !important;
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: 0.5rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-original-title] {
text-decoration: underline;
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
border-bottom: 0;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: .5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
dfn {
font-style: italic;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 80%;
}
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -.25em;
}
sup {
top: -.5em;
}
a {
color: #007bff;
text-decoration: none;
background-color: transparent;
-webkit-text-decoration-skip: objects;
}
a:hover {
color: #0056b3;
text-decoration: underline;
}
a:not([href]):not([tabindex]) {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):focus {
outline: 0;
}
pre,
code,
kbd,
samp {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 1em;
}
pre {
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
-ms-overflow-style: scrollbar;
}
figure {
margin: 0 0 1rem;
}
img {
vertical-align: middle;
border-style: none;
}
svg {
overflow: hidden;
vertical-align: middle;
}
table {
border-collapse: collapse;
}
caption {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
color: #6c757d;
text-align: left;
caption-side: bottom;
}
th {
text-align: inherit;
}
label {
display: inline-block;
margin-bottom: 0.5rem;
}
button {
border-radius: 0;
}
button:focus {
outline: 1px dotted;
outline: 5px auto -webkit-focus-ring-color;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
html [type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
padding: 0;
border-style: none;
}
input[type="radio"],
input[type="checkbox"] {
box-sizing: border-box;
padding: 0;
}
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"] {
-webkit-appearance: listbox;
}
textarea {
overflow: auto;
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
display: block;
width: 100%;
max-width: 100%;
padding: 0;
margin-bottom: .5rem;
font-size: 1.5rem;
line-height: inherit;
color: inherit;
white-space: normal;
}
progress {
vertical-align: baseline;
}
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
outline-offset: -2px;
-webkit-appearance: none;
}
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
summary {
display: list-item;
cursor: pointer;
}
template {
display: none;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */

File diff suppressed because one or more lines are too long

@ -1,8 +0,0 @@
/*!
* Bootstrap Reboot v4.1.3 (https://getbootstrap.com/)
* Copyright 2011-2018 The Bootstrap Authors
* Copyright 2011-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.min.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,12 +0,0 @@
Copyright (c) .NET Foundation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
these files except in compliance with the License. You may obtain a copy of the
License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

@ -1,432 +0,0 @@
// Unobtrusive validation support library for jQuery and jQuery Validate
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// @version v3.2.11
/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
/*global document: false, jQuery: false */
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define("jquery.validate.unobtrusive", ['jquery-validation'], factory);
} else if (typeof module === 'object' && module.exports) {
// CommonJS-like environments that support module.exports
module.exports = factory(require('jquery-validation'));
} else {
// Browser global
jQuery.validator.unobtrusive = factory(jQuery);
}
}(function ($) {
var $jQval = $.validator,
adapters,
data_validation = "unobtrusiveValidation";
function setValidationValues(options, ruleName, value) {
options.rules[ruleName] = value;
if (options.message) {
options.messages[ruleName] = options.message;
}
}
function splitAndTrim(value) {
return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
}
function escapeAttributeValue(value) {
// As mentioned on http://api.jquery.com/category/selectors/
return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
}
function getModelPrefix(fieldName) {
return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
}
function appendModelPrefix(value, prefix) {
if (value.indexOf("*.") === 0) {
value = value.replace("*.", prefix);
}
return value;
}
function onError(error, inputElement) { // 'this' is the form element
var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
replaceAttrValue = container.attr("data-valmsg-replace"),
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
container.removeClass("field-validation-valid").addClass("field-validation-error");
error.data("unobtrusiveContainer", container);
if (replace) {
container.empty();
error.removeClass("input-validation-error").appendTo(container);
}
else {
error.hide();
}
}
function onErrors(event, validator) { // 'this' is the form element
var container = $(this).find("[data-valmsg-summary=true]"),
list = container.find("ul");
if (list && list.length && validator.errorList.length) {
list.empty();
container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
$.each(validator.errorList, function () {
$("<li />").html(this.message).appendTo(list);
});
}
}
function onSuccess(error) { // 'this' is the form element
var container = error.data("unobtrusiveContainer");
if (container) {
var replaceAttrValue = container.attr("data-valmsg-replace"),
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;
container.addClass("field-validation-valid").removeClass("field-validation-error");
error.removeData("unobtrusiveContainer");
if (replace) {
container.empty();
}
}
}
function onReset(event) { // 'this' is the form element
var $form = $(this),
key = '__jquery_unobtrusive_validation_form_reset';
if ($form.data(key)) {
return;
}
// Set a flag that indicates we're currently resetting the form.
$form.data(key, true);
try {
$form.data("validator").resetForm();
} finally {
$form.removeData(key);
}
$form.find(".validation-summary-errors")
.addClass("validation-summary-valid")
.removeClass("validation-summary-errors");
$form.find(".field-validation-error")
.addClass("field-validation-valid")
.removeClass("field-validation-error")
.removeData("unobtrusiveContainer")
.find(">*") // If we were using valmsg-replace, get the underlying error
.removeData("unobtrusiveContainer");
}
function validationInfo(form) {
var $form = $(form),
result = $form.data(data_validation),
onResetProxy = $.proxy(onReset, form),
defaultOptions = $jQval.unobtrusive.options || {},
execInContext = function (name, args) {
var func = defaultOptions[name];
func && $.isFunction(func) && func.apply(form, args);
};
if (!result) {
result = {
options: { // options structure passed to jQuery Validate's validate() method
errorClass: defaultOptions.errorClass || "input-validation-error",
errorElement: defaultOptions.errorElement || "span",
errorPlacement: function () {
onError.apply(form, arguments);
execInContext("errorPlacement", arguments);
},
invalidHandler: function () {
onErrors.apply(form, arguments);
execInContext("invalidHandler", arguments);
},
messages: {},
rules: {},
success: function () {
onSuccess.apply(form, arguments);
execInContext("success", arguments);
}
},
attachValidation: function () {
$form
.off("reset." + data_validation, onResetProxy)
.on("reset." + data_validation, onResetProxy)
.validate(this.options);
},
validate: function () { // a validation function that is called by unobtrusive Ajax
$form.validate();
return $form.valid();
}
};
$form.data(data_validation, result);
}
return result;
}
$jQval.unobtrusive = {
adapters: [],
parseElement: function (element, skipAttach) {
/// <summary>
/// Parses a single HTML element for unobtrusive validation attributes.
/// </summary>
/// <param name="element" domElement="true">The HTML element to be parsed.</param>
/// <param name="skipAttach" type="Boolean">[Optional] true to skip attaching the
/// validation to the form. If parsing just this single element, you should specify true.
/// If parsing several elements, you should specify false, and manually attach the validation
/// to the form when you are finished. The default is false.</param>
var $element = $(element),
form = $element.parents("form")[0],
valInfo, rules, messages;
if (!form) { // Cannot do client-side validation without a form
return;
}
valInfo = validationInfo(form);
valInfo.options.rules[element.name] = rules = {};
valInfo.options.messages[element.name] = messages = {};
$.each(this.adapters, function () {
var prefix = "data-val-" + this.name,
message = $element.attr(prefix),
paramValues = {};
if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy)
prefix += "-";
$.each(this.params, function () {
paramValues[this] = $element.attr(prefix + this);
});
this.adapt({
element: element,
form: form,
message: message,
params: paramValues,
rules: rules,
messages: messages
});
}
});
$.extend(rules, { "__dummy__": true });
if (!skipAttach) {
valInfo.attachValidation();
}
},
parse: function (selector) {
/// <summary>
/// Parses all the HTML elements in the specified selector. It looks for input elements decorated
/// with the [data-val=true] attribute value and enables validation according to the data-val-*
/// attribute values.
/// </summary>
/// <param name="selector" type="String">Any valid jQuery selector.</param>
// $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one
// element with data-val=true
var $selector = $(selector),
$forms = $selector.parents()
.addBack()
.filter("form")
.add($selector.find("form"))
.has("[data-val=true]");
$selector.find("[data-val=true]").each(function () {
$jQval.unobtrusive.parseElement(this, true);
});
$forms.each(function () {
var info = validationInfo(this);
if (info) {
info.attachValidation();
}
});
}
};
adapters = $jQval.unobtrusive.adapters;
adapters.add = function (adapterName, params, fn) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="params" type="Array" optional="true">[Optional] An array of parameter names (strings) that will
/// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
/// mmmm is the parameter name).</param>
/// <param name="fn" type="Function">The function to call, which adapts the values from the HTML
/// attributes into jQuery Validate rules and/or messages.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
if (!fn) { // Called with no params, just a function
fn = params;
params = [];
}
this.push({ name: adapterName, params: params, adapt: fn });
return this;
};
adapters.addBool = function (adapterName, ruleName) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation rule has no parameter values.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
/// of adapterName will be used instead.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, function (options) {
setValidationValues(options, ruleName || adapterName, true);
});
};
adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
/// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="minRuleName" type="String">The name of the jQuery Validate rule to be used when you only
/// have a minimum value.</param>
/// <param name="maxRuleName" type="String">The name of the jQuery Validate rule to be used when you only
/// have a maximum value.</param>
/// <param name="minMaxRuleName" type="String">The name of the jQuery Validate rule to be used when you
/// have both a minimum and maximum value.</param>
/// <param name="minAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
/// contains the minimum value. The default is "min".</param>
/// <param name="maxAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
/// contains the maximum value. The default is "max".</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
var min = options.params.min,
max = options.params.max;
if (min && max) {
setValidationValues(options, minMaxRuleName, [min, max]);
}
else if (min) {
setValidationValues(options, minRuleName, min);
}
else if (max) {
setValidationValues(options, maxRuleName, max);
}
});
};
adapters.addSingleVal = function (adapterName, attribute, ruleName) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation rule has a single value.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>
/// <param name="attribute" type="String">[Optional] The name of the HTML attribute that contains the value.
/// The default is "val".</param>
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
/// of adapterName will be used instead.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, [attribute || "val"], function (options) {
setValidationValues(options, ruleName || adapterName, options.params[attribute]);
});
};
$jQval.addMethod("__dummy__", function (value, element, params) {
return true;
});
$jQval.addMethod("regex", function (value, element, params) {
var match;
if (this.optional(element)) {
return true;
}
match = new RegExp(params).exec(value);
return (match && (match.index === 0) && (match[0].length === value.length));
});
$jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
var match;
if (nonalphamin) {
match = value.match(/\W/g);
match = match && match.length >= nonalphamin;
}
return match;
});
if ($jQval.methods.extension) {
adapters.addSingleVal("accept", "mimtype");
adapters.addSingleVal("extension", "extension");
} else {
// for backward compatibility, when the 'extension' validation method does not exist, such as with versions
// of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for
// validating the extension, and ignore mime-type validations as they are not supported.
adapters.addSingleVal("extension", "extension", "accept");
}
adapters.addSingleVal("regex", "pattern");
adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength");
adapters.add("equalto", ["other"], function (options) {
var prefix = getModelPrefix(options.element.name),
other = options.params.other,
fullOtherName = appendModelPrefix(other, prefix),
element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0];
setValidationValues(options, "equalTo", element);
});
adapters.add("required", function (options) {
// jQuery Validate equates "required" with "mandatory" for checkbox elements
if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
setValidationValues(options, "required", true);
}
});
adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
var value = {
url: options.params.url,
type: options.params.type || "GET",
data: {}
},
prefix = getModelPrefix(options.element.name);
$.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
var paramName = appendModelPrefix(fieldName, prefix);
value.data[paramName] = function () {
var field = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']");
// For checkboxes and radio buttons, only pick up values from checked fields.
if (field.is(":checkbox")) {
return field.filter(":checked").val() || field.filter(":hidden").val() || '';
}
else if (field.is(":radio")) {
return field.filter(":checked").val() || '';
}
return field.val();
};
});
setValidationValues(options, "remote", value);
});
adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
if (options.params.min) {
setValidationValues(options, "minlength", options.params.min);
}
if (options.params.nonalphamin) {
setValidationValues(options, "nonalphamin", options.params.nonalphamin);
}
if (options.params.regex) {
setValidationValues(options, "regex", options.params.regex);
}
});
adapters.add("fileextensions", ["extensions"], function (options) {
setValidationValues(options, "extension", options.params.extensions);
});
$(function () {
$jQval.unobtrusive.parse(document);
});
return $jQval.unobtrusive;
}));

File diff suppressed because one or more lines are too long

@ -1,22 +0,0 @@
The MIT License (MIT)
=====================
Copyright Jörn Zaefferer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

@ -1,36 +0,0 @@
Copyright JS Foundation and other contributors, https://js.foundation/
This software consists of voluntary contributions made by many
individuals. For exact contribution history, see the revision history
available at https://github.com/jquery/jquery
The following license applies to all parts of this software except as
documented below:
====
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
====
All files located in the node_modules and external directories are
externally maintained libraries used by this software which have their
own licenses; we recommend you read them, as their terms may differ from
the terms above.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -136,7 +136,7 @@
</script>
<script>
const connection = new signalR.HubConnectionBuilder()
.withUrl('http://192.168.3.84:8080/hub?group=appuser')
.withUrl('http://192.168.3.124:8000/hub?group=appuser')
.build();
connection.on("receive", function (message) {
console.log(message);

@ -48,7 +48,7 @@ namespace Infrastructure.Extensions
}
}
}
var ip = ipList.Where(o => !o.ToString().StartsWith("127")).FirstOrDefault();
var ip = ipList.Where(o => o.ToString().StartsWith("192")).FirstOrDefault();
return ip;
}

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

@ -221,6 +221,7 @@ namespace Infrastructure.Web
{
app.UseAuthentication();
}
public virtual void OnModelCreating(ModelBuilder modelBuilder)
{
}

@ -57,11 +57,10 @@ namespace StudyCenter.Controllers
public IActionResult Logout()
{
//var fullReturnUrl = Url.FullAction("Index", "Home");
//var logoutUrl = this._configuration["usercenter:logout"];
//var url = logoutUrl.SetParam("returnUrl", fullReturnUrl);
//return Redirect(url);
return SignOut("Cookies", "oidc");
var fullReturnUrl = Url.FullAction("Index", "Home");
var logoutUrl = this._configuration["usercenter:logout"];
var url = logoutUrl.SetParam("returnUrl", fullReturnUrl);
return Redirect(url);
}
public string JsonpLogout(string userName, string timestamp, string sign)
@ -86,10 +85,14 @@ namespace StudyCenter.Controllers
}
}
[Authorize]
public IActionResult Login()
[HttpGet]
[AllowAnonymous]
public IActionResult Login(string returnUrl = null)
{
return RedirectToAction("Index", "Home");
var fullReturnUrl = Url.GetFullUrl(returnUrl ?? "~");
var loginUrl = this._configuration["usercenter:login"];
var url = loginUrl.SetParam(nameof(returnUrl), fullReturnUrl);
return Redirect(url);
}
[AllowAnonymous]

@ -1,46 +0,0 @@
using System.Linq;
using Application.Domain.Entities;
using Application.Models;
using Infrastructure.Data;
using Infrastructure.Extensions;
using Infrastructure.Web;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace StudyCenter.Controllers
{
public class CourseController : BaseController
{
private readonly IRepository<CourseCategory> _courseCategoryRepo;
private readonly IRepository<Course> _courseRepo;
public CourseController(IRepository<CourseCategory> courseCategoryRepo, IRepository<Course> courseRepo)
{
this._courseCategoryRepo = courseCategoryRepo;
this._courseRepo = courseRepo;
}
public IActionResult Index(CourseModel model)
{
var categoyies = this._courseCategoryRepo.ReadOnlyTable().Include(o => o.Parent).ToList();
model.Categories = categoyies;
var query = this._courseRepo.ReadOnlyTable();
if (model.CategoryId.HasValue)
{
var category = categoyies.FirstOrDefault(o => o.Id == model.CategoryId.Value);
query = query.Where(o => o.Category.Path.StartsWith(category.Path));
}
query = query.OrderBy(o => o.Category.DisplayOrder)
.ThenBy(o => o.Category.Number)
.ThenBy(o => o.DisplayOrder)
.ThenBy(o => o.Number);
model.TotalCount = query.Count();
model.List = query.Paged(model.PageIndex, model.PageSize);
foreach (var item in model.List)
{
item.Category = categoyies.FirstOrDefault(o => o.Id == item.CategoryId);
}
return View(model);
}
}
}

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Threading.Tasks;
using Application.Domain.Entities;
@ -12,7 +11,6 @@ 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;
@ -34,58 +32,28 @@ namespace StudyCenter
base.ConfigureServices(services);
}
public override void AddAuthentication(IServiceCollection services)
public override Task ValidatePrincipal(CookieValidatePrincipalContext arg)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies", o =>
return Task.Run(() =>
{
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
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))
{
OnTicketReceived = o =>
{
return Task.CompletedTask;
}
};
arg.HttpContext.SignOutAsync();
arg.HttpContext.SignIn(userName, userPermissions, arg.Properties.IsPersistent);
}
});
}
public override Task ValidatePrincipal(CookieValidatePrincipalContext arg)
{
var userRepo = arg.HttpContext.RequestServices.GetService<IRepository<User>>();
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)
{
modelBuilder.Entity<PermissionCategory>().HasOne(o => o.Parent).WithMany(o => o.Children).HasForeignKey(o => o.ParentId);

@ -0,0 +1,11 @@
namespace Application.Models
{
public class Chat
{
public string Id { get; set; }
public string FromName { get; set; }
public string ToId { get; set; }
public string Type { get; set; }
}
}

@ -1,14 +1,5 @@
namespace ApiGateway.Models
namespace Application.Models
{
public class Chat
{
public string Id { get; set; }
public string FromName { get; set; }
public string ToId { get; set; }
public string Type { get; set; }
}
public class Message
{
public string Id { get; set; }

@ -1,24 +0,0 @@
using Application.Domain.Entities;
using IdentityServer4.Stores;
using Infrastructure.Data;
using Infrastructure.Extensions;
using System.Linq;
using System.Threading.Tasks;
namespace UserCenter
{
public class ClientStore : IClientStore
{
private readonly IRepository<Client> _clientRepo;
public ClientStore(IRepository<Client> clientRepo)
{
this._clientRepo = clientRepo;
}
Task<IdentityServer4.Models.Client> IClientStore.FindClientByIdAsync(string clientId)
{
return Task.FromResult(this._clientRepo.ReadOnlyTable().FirstOrDefault(o => o.ClientId == clientId).To<IdentityServer4.Models.Client>());
}
}
}

@ -1,74 +0,0 @@
// 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");
}
}
}

@ -1,16 +0,0 @@
// 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; }
}
}

@ -1,16 +0,0 @@
// 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";
}
}

@ -1,191 +0,0 @@
// 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
};
}
}
}

@ -1,19 +0,0 @@
// 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; }
}
}

@ -1,18 +0,0 @@
// 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; }
}
}

@ -1,16 +0,0 @@
// 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; }
}
}

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

@ -1,8 +1,12 @@
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 Application.Domain.Entities;
using Application.Models;
using IdentityModel;
using IdentityServer4.Events;
using IdentityServer4.Services;
using Infrastructure.Data;
using Infrastructure.Email;
using Infrastructure.Extensions;
@ -12,24 +16,12 @@ 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
{
@ -43,7 +35,6 @@ namespace UserCenter.Controllers
private readonly IEncryptionService _encryptionService;
private readonly IEmailSender _emailSender;
private readonly ISmsSender _smsSender;
private readonly IEventService _events;
public AccountController(IConfiguration cfg,
IRepository<User> userRepo,
@ -51,9 +42,7 @@ namespace UserCenter.Controllers
IEncryptionService encryptionService,
IStringLocalizer<Resource> localizer,
IEmailSender emaliSender,
ISmsSender smsSender,
IEventService events
)
ISmsSender smsSender)
{
this._cfg = cfg;
this._userRepo = userRepo;
@ -62,7 +51,6 @@ namespace UserCenter.Controllers
this._localizer = localizer;
this._emailSender = emaliSender;
this._smsSender = smsSender;
this._events = events;
}
#region 用户中心
@ -172,20 +160,34 @@ namespace UserCenter.Controllers
}
if (success)
{
this._events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id.ToString(), user.UserName));
var roles = this._userRepo.ReadOnlyTable().Where(o => o.UserName == userName)
var userPermissions = 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();
Microsoft.AspNetCore.Http.AuthenticationManagerExtensions.SignInAsync(HttpContext, user.Id.ToString(), user.UserName, new AuthenticationProperties { IsPersistent = model.RememberMe }, roles.Select(o => new Claim("role", o)).ToArray());
HttpContext.SignIn(model.UserName, userPermissions, model.RememberMe);
if (string.IsNullOrEmpty(returnUrl))
{
returnUrl = Url.Action("Index", "Home");
}
ViewBag.Url = Url.IsLocalUrl(returnUrl) ? Url.GetFullUrl("~") : returnUrl;
var urls = new List<string>();
var list = this._siteRepo.ReadOnlyTable().ToList();
foreach (var site in list)
{
var username = user.UserName;
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
var sign = string.Concat(userName, timestamp, site.Key).Md5();
var url = site.Login
.SetParam(nameof(username), username)
.SetParam(nameof(timestamp), timestamp)
.SetParam("rememberme", model.RememberMe)
.SetParam(nameof(sign), sign);
urls.Add(url);
}
Response.Headers.Remove("Location");
return this.Redirect(returnUrl);
return View("JsonpLogin", urls);
}
else
{
@ -206,78 +208,10 @@ namespace UserCenter.Controllers
ModelState.AddModelError("", ex.Message);
}
}
this._events.RaiseAsync(new UserLoginFailureEvent(model.UserName, "invalid credentials"));
ViewData["ReturnUrl"] = returnUrl;
return View(model);
}
[AllowAnonymous]
[HttpPost]
public async Task<IActionResult> OAuthLogin([FromForm] string provider)
{
// Note: the "provider" parameter corresponds to the external
// authentication provider choosen by the user agent.
if (string.IsNullOrWhiteSpace(provider))
{
return BadRequest();
}
if (!await HttpContext.IsProviderSupportedAsync(provider))
{
return BadRequest();
}
// Instruct the middleware corresponding to the requested external identity
// provider to redirect the user agent to its own authorization endpoint.
// Note: the authenticationScheme parameter must match the value configured in Startup.cs
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 注册

@ -1,13 +1,13 @@
using System;
using System;
using System.Linq;
using ApiGateway.Models;
using Application.Models;
using Infrastructure.Extensions;
using Infrastructure.Web.SignalR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Raven.Embedded;
namespace ApiGateway.Controllers
namespace UserCenter.Controllers
{
public class MessageController : Controller
{

@ -1,19 +0,0 @@
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;
}
}
}

@ -15,7 +15,7 @@ namespace UserCenter
.Run<Startup>(new List<EFConfigurationValue> {
new EFConfigurationValue { Id = "openapi.title", Value= "web api" },
new EFConfigurationValue { Id = "openapi.version", Value= "1.0" },
new EFConfigurationValue { Id = "server.urls", Value= "http://*:80" },
new EFConfigurationValue { Id = "server.urls", Value= "http://*:8000" },
new EFConfigurationValue { Id = "security:key", Value= "111111111111111111111111"},
new EFConfigurationValue { Id = "security:iv", Value= "11111111"},
new EFConfigurationValue { Id = "jwt:key", Value= "111111111111111111111111"},

@ -3,7 +3,7 @@
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:80",
"applicationUrl": "http://localhost:8000",
"sslPort": 0
}
},
@ -21,7 +21,7 @@
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:80"
"applicationUrl": "http://localhost:8000"
}
}
}

@ -1,118 +0,0 @@
using Application.Domain.Entities;
using IdentityServer4.Models;
using IdentityServer4.Validation;
using Infrastructure.Data;
using Infrastructure.Security;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace UserCenter
{
public class ResourceOwnerValidator : IResourceOwnerPasswordValidator
{
private readonly IConfiguration _cfg;
private readonly IRepository<User> _userRepo;
private readonly IEncryptionService _encryptionService;
public ResourceOwnerValidator(IConfiguration cfg, IRepository<User> userRepo, IEncryptionService encryptionService)
{
this._cfg = cfg;
this._userRepo = userRepo;
this._encryptionService = encryptionService;
}
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");
// 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);
//}
return Task.CompletedTask;
}
}
}

@ -1,43 +0,0 @@
// 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,7 +1,4 @@
using Application.Domain.Entities;
using IdentityModel;
using IdentityServer4;
using IdentityServer4.Models;
using Infrastructure.Data;
using Infrastructure.Domain;
using Infrastructure.Email;
@ -11,17 +8,18 @@ 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 Microsoft.Extensions.Logging;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using Raven.Embedded;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace UserCenter
@ -30,6 +28,7 @@ namespace UserCenter
{
public Startup(IConfiguration configuration, IHostingEnvironment env) : base(configuration, env)
{
EmbeddedServer.Instance.StartServer();
}
public override void ConfigureServices(IServiceCollection services)
@ -37,111 +36,13 @@ namespace UserCenter
base.ConfigureServices(services);
services.AddTransient<IEmailSender, EmptyEmailSender>();
services.AddTransient<ISmsSender, EmptySmsSender>();
services.AddOcelot();
}
public override void AddAuthentication(IServiceCollection services)
public override void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
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" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile
}
}
})
.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 =>
// {
// opts.Cookie.Name = this.GetType().FullName;
// opts.LoginPath = "/Account/Login";
// opts.LogoutPath = "/Account/Logout";
// opts.AccessDeniedPath = "/Account/AccessDenied";
// //不配置SessionStore则存储到cookie
// var useCookieSessionStore = this._cfg.GetSection("AppSettings").GetValue<bool>("UseCookieSessionStore");
// if (!useCookieSessionStore)
// {
// opts.SessionStore = services.BuildServiceProvider().GetService<ITicketStore>();
// }
// opts.Events = new CookieAuthenticationEvents
// {
// //OnRedirectToLogin = RedirectToLogin(),
// OnValidatePrincipal = ValidatePrincipal
// };
// })
// .AddGitHub(options =>
// {
// options.ClientId = "6ec6712a4dbbe3f1f1ac";
// options.ClientSecret = "ea91f08553a3b242340a905fb000d5a828d9a69e";
// })
//.AddQQ(o =>
//{
// //https://connect.qq.com/manage.html
// o.ClientId = "101569040";
// o.ClientSecret = "5541d994fe8f3b3fa428c63a47139b39";
//});
}
public override void UseAuthentication(IApplicationBuilder app)
{
app.UseIdentityServer();
base.Configure(app, env, loggerFactory);
app.UseOcelot().Wait();
}
public override Task ValidatePrincipal(CookieValidatePrincipalContext arg)
@ -183,8 +84,6 @@ namespace UserCenter
//关系
modelBuilder.Entity<Site>();
modelBuilder.Entity<Site>().HasIndex(o => o.Name).IsUnique();
//identity
//modelBuilder.Entity<Client>().HasIndex(o => o.ClientId).IsUnique();
}
public override void Seed(DbContext dbContext, IServiceProvider serviceProvider, IConfiguration configuration)

@ -11,6 +11,8 @@
<PackageReference Include="IdentityServer4.EntityFramework" Version="2.4.0" />
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
<PackageReference Include="Ocelot" Version="13.5.0" />
<PackageReference Include="RavenDB.Embedded" Version="4.1.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Infrastructure\Infrastructure.csproj" />

@ -1,82 +0,0 @@
@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>

@ -1,34 +0,0 @@
@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,5 +8,4 @@
@using Infrastructure.Data
@using Application.Domain.Entities
@using Application.Models
@using IdentityServer4.Quickstart.UI
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@ -1 +0,0 @@
{"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="}}

@ -9,8 +9,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UserCenter", "UserCenter\Us
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StudyCenter", "StudyCenter\StudyCenter.csproj", "{F095AE4D-D768-46C8-8BBF-3314B82C4CC7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApiGateway", "ApiGateway\ApiGateway.csproj", "{9F3FFDF0-F35E-4BBD-95C6-F9FC98CC9C2C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IoTCenter", "IoTCenter\IoTCenter.csproj", "{216F0A25-9F20-4235-9316-632AB94E854A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IoT", "IoT", "{B39CEABB-9A42-4BA2-A167-665349113986}"
@ -37,6 +35,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IoT.Shared", "IoT\IoT.Share
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IoT.UI.Shard", "IoT\IoT.UI.Shard\IoT.UI.Shard.csproj", "{1F466C72-FD35-483E-A199-2C143CB813C1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Infrastructure", "Infrastructure", "{AF2F6203-A338-4B48-8FED-5D6385663665}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -55,10 +55,6 @@ Global
{F095AE4D-D768-46C8-8BBF-3314B82C4CC7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F095AE4D-D768-46C8-8BBF-3314B82C4CC7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F095AE4D-D768-46C8-8BBF-3314B82C4CC7}.Release|Any CPU.Build.0 = Release|Any CPU
{9F3FFDF0-F35E-4BBD-95C6-F9FC98CC9C2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9F3FFDF0-F35E-4BBD-95C6-F9FC98CC9C2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9F3FFDF0-F35E-4BBD-95C6-F9FC98CC9C2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9F3FFDF0-F35E-4BBD-95C6-F9FC98CC9C2C}.Release|Any CPU.Build.0 = Release|Any CPU
{216F0A25-9F20-4235-9316-632AB94E854A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{216F0A25-9F20-4235-9316-632AB94E854A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{216F0A25-9F20-4235-9316-632AB94E854A}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -108,6 +104,7 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{264A3E6B-80A1-488D-841D-930B810B85D2} = {AF2F6203-A338-4B48-8FED-5D6385663665}
{2A80F0AD-9ADB-464C-BF31-06E505D1793B} = {B39CEABB-9A42-4BA2-A167-665349113986}
{F48CA65D-B2D6-4DB8-A396-A3FE913804FB} = {B39CEABB-9A42-4BA2-A167-665349113986}
{81F8D3B6-6033-45D7-BF23-8FA293FF7D9B} = {2A80F0AD-9ADB-464C-BF31-06E505D1793B}

Loading…
Cancel
Save