IdentityServer4 for ASP.NET WEB Applications (单点登录统一认证)
服务端
新建ASP.NET Core Web MVC 项目
SSOServer
NuGet安装IdentityServer4
新建Config.cs类
public class Config
{
// scopes define the resources in your system
public static IEnumerable GetIdentityResources()
{
return new List
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
};
}
// clients want to access resources (aka scopes)
public static IEnumerable GetClients()
{
return new List
{
// OpenID Connect隐式流客户端(MVC)
new Client
{
ClientId = "mvc",
ClientName = "MVC Client",
AllowedGrantTypes = GrantTypes.Implicit,//隐式方式
RequireConsent=false,//如果不需要显示否同意授权 页面 这里就设置为false
RedirectUris = { "http://localhost:5002/signin-oidc" },//登录成功后返回的客户端地址
PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },//注销登录后返回的客户端地址
AllowedScopes =//下面这两个必须要加吧 不太明白啥意思
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile
}
}
};
}
}
Startup.cs中注入IdentityServer4
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
// 注入IdentityServer
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryClients(Config.GetClients());
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseRouting();
// 注入IdentityServer
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
项目属性中将调试端口改为5000
调试访问
https://localhost:5000/.well-known/openid-configuration
能正常访问JSON即可.
增加登陆控制
AccountController
using Microsoft.AspNetCore.Mvc;
using System;
using System.Threading.Tasks;
using IdentityServer4;
using Microsoft.AspNetCore.Http;
namespace SSOServer.Controllers
{
public class AccountController : Controller
{
///
/// 登录页面
///
[HttpGet]
public async Task Login(string returnUrl = null)
{
ViewData["returnUrl"] = returnUrl;
return View();
}
///
/// 登录post回发处理
///
[HttpPost]
public async Task Login(string userName, string password, string returnUrl = null)
{
ViewData["returnUrl"] = returnUrl;
if (userName=="test" && password=="test")
{
Microsoft.AspNetCore.Authentication.AuthenticationProperties props = new Microsoft.AspNetCore.Authentication.AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromDays(1))
};
await HttpContext.SignInAsync(new IdentityServerUser(Guid.NewGuid().ToString()){DisplayName = userName},props); // 来源于Microsoft.AspNetCore.Http扩展
if (returnUrl != null)
{
return Redirect(returnUrl);
}
return View();
}
else
{
return View();
}
}
}
}
登陆视图
@{
Layout = null;
}
Login
统一认证登录中心
测试登陆
http://localhost:5000/Account/Login
可以安装Swashbuckle.AspNetCore以备调试
swgger配置方式参考这里:
https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/getting-started-with-swashbuckle?view=aspnetcore-5.0&tabs=visual-studio
客户端(Core)
新建ASP.NET Core Web MVC项目
Core.Client
-
NuGet安装IdentityServer4.AccessTokenValidation
-
NuGet安装Microsoft.AspNetCore.Authentication.OpenIdConnect
-
Startup配置
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.IdentityModel.Tokens.Jwt;
namespace Core.Client
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); // System.IdentityModel.Tokens.Jwt
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ClientId = "mvc";
options.SaveTokens = true;
});
services.AddControllersWithViews();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
Home控制器中增加认证标识
[Microsoft.AspNetCore.Authorization.Authorize]
调试
这一步骤中,坑最多.
首先,大部分新浏览器(IE除外),已经不支持SameSite=None & Secure=null的用法
因此试用了网上的SameSiteCookiesServiceCollectionExtensions
等方法都行不通
将所有站点改为HTTPS站点后,问题解决
客户端(Non Core)
新建ASP.NET Web MVC项目
Web.Client
站点属性端口改为44301
安装依赖程序包
NuGet安装Microsoft.Owin.Host.SystemWeb
NuGet安装Microsoft.Owin.Security.OpenIdConnect
NuGet安装Microsoft.Owin.Security.Cookies
SSOServer项目的Cofig.GetClients增加站点配置
new Client
{
ClientName = ".NET 4 MVC website",
ClientId = "net4mvcclient",
ClientSecrets =
{
new Secret("secret3".Sha256())
},
AllowedGrantTypes = GrantTypes.Implicit, //隐式流
RequireConsent = false,
AllowOfflineAccess = true,
AllowAccessTokensViaBrowser = true, //To be able to get the token via browser
RedirectUris = { "https://localhost:44301/signin-oidc" },
PostLogoutRedirectUris = { "https://localhost:44301" }, //An existing route on MVC client
AllowedScopes = {"openid", "profile", "offline_access", "api1", "api2" }
},
配置cookie中间件
更改 ASP.NET MVC项目的Startup类代码,将OpenID Connect中间件指向IdentityServer4实例。
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Owin;
[assembly: OwinStartup(typeof(Web.Client.Startup))]
namespace Web.Client
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
// 有关如何配置应用程序的详细信息,请访问 https://go.microsoft.com/fwlink/?LinkID=316888
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "https://localhost:5000",
ClientId = "net4mvcclient",
ClientSecret = "secret3",
RedirectUri = "https://localhost:44301/signin-oidc",
PostLogoutRedirectUri = "https://localhost:44301", //Same value as set on Config.cs on IdentityServer
ResponseType = "id_token token", // to get id_token + access_token
RequireHttpsMetadata = false,
TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
NameClaimType = "name"
}, // This is to set Identity.Name
SignInAsAuthenticationType = "Cookies"
});
}
}
}
HomeController.Contact增加认证
[Authorize]
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
调试测试
测试登录跳转以及认证访问正常
客户端(Wisej)
创建项目
Wisej.Client
创建文件夹Controllers & Views
添加MVC5依赖项
Visual Studio 已向项目“Wisej.Client”添加 ASP.NET MVC 5 的 全部集合 个依赖项。
项目中的 Global.asax.cs 文件可能需要其他更改才能启用 ASP.NET MVC。
1. 添加以下命名空间引用:
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Optimization;
2. 如果代码尚未定义 Application_Start 方法,请添加以下方法:
protected void Application_Start()
{
}
3. 在 Application_Start 方法的末尾添加以下行:
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
BundleConfig.RegisterBundles(BundleTable.Bundles);
安装依赖程序包
NuGet安装Microsoft.AspNet.Mvc (MVC基架)
NuGet安装Microsoft.AspNet.Web.Optimization (MVC基架)
NuGet安装bootstrap (MVC基架)
NuGet安装Microsoft.Owin.Host.SystemWeb
NuGet安装Microsoft.Owin.Security.OpenIdConnect
NuGet安装Microsoft.Owin.Security.Cookies
SSOServer项目的Cofig.GetClients增加站点配置
new Client
{
ClientName = "Wisej Client",
ClientId = "wisejclient",
ClientSecrets =
{
new Secret("secret3".Sha256())
},
AllowedGrantTypes = GrantTypes.Implicit, //隐式流
RequireConsent = false,
AllowOfflineAccess = true,
AllowAccessTokensViaBrowser = true, //To be able to get the token via browser
RedirectUris = {"https://localhost:44302/signin-oidc"},
PostLogoutRedirectUris = {"https://localhost:44302"}, //An existing route on MVC client
AllowedScopes = {"openid", "profile", "offline_access", "api1", "api2"}
},
配置cookie中间件
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Owin;
[assembly: OwinStartup(typeof(Wisej.Client.Startup))]
namespace Wisej.Client
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
// 有关如何配置应用程序的详细信息,请访问 https://go.microsoft.com/fwlink/?LinkID=316888
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "https://localhost:5000",
ClientId = "wisejclient",
ClientSecret = "secret3",
RedirectUri = "https://localhost:44302/signin-oidc",
PostLogoutRedirectUri = "https://localhost:44302", //Same value as set on Config.cs on IdentityServer
ResponseType = "id_token token", // to get id_token + access_token
RequireHttpsMetadata = false,
TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
NameClaimType = "name"
}, // This is to set Identity.Name
SignInAsAuthenticationType = "Cookies"
});
}
}
}
RouteConfig兼容配置
using System.Web.Mvc;
using System.Web.Routing;
namespace Wisej.Client
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{resource}.html/{*pathInfo}");
routes.IgnoreRoute("{resource}.wx/{*pathInfo}");
routes.IgnoreRoute("{resource}.json");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { action = "Index", id = UrlParameter.Optional }
);
}
}
}
实现统一登录认证
如果SSOServer没启动,将出现下以下错误.
“/”应用程序中的服务器错误。
由于目标计算机积极拒绝,无法连接。 127.0.0.1:5000
说明: 执行当前 Web 请求期间,出现未经处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。
异常详细信息: System.Net.Sockets.SocketException: 由于目标计算机积极拒绝,无法连接。 127.0.0.1:5000
或者
“/”应用程序中的服务器错误。
由于意外的数据包格式,握手失败。
说明: 执行当前 Web 请求期间,出现未经处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。
异常详细信息: System.IO.IOException: 由于意外的数据包格式,握手失败。
源错误:
执行当前 Web 请求期间生成了未经处理的异常。可以使用下面的异常堆栈跟踪信息确定有关异常原因和发生位置的信息。
调试测试
登录认证成功