入门教程:.NET开源OpenID Connect 和OAuth解决方案IdentityServer v3 MVC认证与授权(四)

本教程将搭建一个最小能够运行的IdentityServer。为简单起见,我们将identityserver和客户端放在同一Web应用程序-这可能不会是一个很现实的情况下,但可以让你不太复杂的开始。

完整的源代码可以在这里找到。

Part 1 - MVC MVC认证与授权

在第一部分中我们将创建一个简单的MVC应用程序并添加认证通过identityserver它。然后,我们将有一个更仔细的看claims,claims的变化和授权.

创建一个 web application

在Visual Studio 2013中,创建一个标准的MVC应用程序和设置认证,“没有认证”。

你可以在属性窗口启用SSL

注意:不要忘记更新你的项目属性中的url

添加 IdentityServer 引用

IdentityServer基于OWIN/Katana作为NuGet包。要将其添加到新创建的应用程序上,安装以下2个包:

install-package Microsoft.Owin.Host.Systemweb
install-package Thinktecture.IdentityServer3

IdentityServer配置——客户端

IdentityServer需要一些关于客户端信息,这可以简单地提供使用客户端对象:

public static class Clients
{
    public static IEnumerable<Client> Get()
    {
        return new[]
        {
            new Client
            {
                Enabled = true,
                ClientName = "MVC Client",
                ClientId = "mvc",
                Flow = Flows.Implicit,

                RedirectUris = new List<string>
                {
                    "https://localhost:44319/"
                }
            }
        };
    }
}

IdentityServer配置——用户

下一步我们将添加一些IdentityServer用户-这里通过提供一个简单的C#类完成,当然你可以从任何数据存储加载用户。我们提供了ASP.NET Identity 和MembershipReboot支持检索用户信息。

public static class Users
{
    public static List<InMemoryUser> Get()
    {
        return new List<InMemoryUser>
        {
            new InMemoryUser
            {
                Username = "bob",
                Password = "secret",
                Subject = "1",

                Claims = new[]
                {
                    new Claim(Constants.ClaimTypes.GivenName, "Bob"),
                    new Claim(Constants.ClaimTypes.FamilyName, "Smith")
                }
            }
        };
    }
}

添加 Startup.cs

配置启动类。在这里,我们提供有关客户信息的用户,范围,签名证书和其他一些配置选项。生产要从Windows证书存储区或其他固定源负载签名证书。这里我们简单地添加到项目文件(你可以下载一个测试证书的地方。它添加该项目并将其属性【复制到输出目录】更改为始终复制。

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.Map("/identity", idsrvApp =>
            {
                idsrvApp.UseIdentityServer(new IdentityServerOptions
                {
                    SiteName = "Embedded IdentityServer",
                    SigningCertificate = LoadCertificate(),

                    Factory = InMemoryFactory.Create(
                        users  : Users.Get(),
                        clients: Clients.Get(),
                        scopes : StandardScopes.All)
                });
            });
    }

    X509Certificate2 LoadCertificate()
    {
        return new X509Certificate2(
            string.Format(@"{0}\bin\identityServer\idsrv3test.pfx", AppDomain.CurrentDomain.BaseDirectory), "idsrv3test");
    }
}

在浏览器中输入以下地址以检查配置https://localhost:44319/identity/.well-known/openid-configuration

注意:

最后一件事,在配置文件中添加下面的代码,否则我们的一些嵌入式资产将不能正确使用IIS加载

<system.webServer>
  <modules runAllManagedModulesForAllRequests="true" />
</system.webServer>

添加和配置OpenID Connect 中间件

增加OIDC 认证的MVC应用程序中,我们需要添加两包:

install-package Microsoft.Owin.Security.Cookies
install-package Microsoft.Owin.Security.OpenIdConnect

在startup.cs中配置默认认证类型为cookie

app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = "Cookies"
    });

使用嵌入的OpenID Connect Server

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
    {
        Authority = "https://localhost:44319/identity",
        ClientId = "mvc",
        RedirectUri = "https://localhost:44319/",
        ResponseType = "id_token",

        SignInAsAuthenticationType = "Cookies"
    });

添加一个受保护的资源和Claims

一个受保护的资源:

[Authorize]
public ActionResult About()
{
    return View((User as ClaimsPrincipal).Claims);
}

相应的视图看起来像这样:

@model IEnumerable<System.Security.Claims.Claim>

<dl>
    @foreach (var claim in Model)
    {
        <dt>@claim.Type</dt>
        <dd>@claim.Value</dd>
    }
</dl>

Authentication and claims

点击About链接将触发认证。identityserver将显示登录页面

登录成功后可以看到登录信息:

增加Role Claim 和 Scope

在下一步中,我们要向我们的用户添加一些角色声明,我们将在以后使用它来进行授权。

现在我们有了OIDC 标准scope-定义一个角色的scope包括claims,和一些标准属性:

public static class Scopes
{
    public static IEnumerable<Scope> Get()
    {
        var scopes = new List<Scope>
        {
            new Scope
            {
                Enabled = true,
                Name = "roles",
                Type = ScopeType.Identity,
                Claims = new List<ScopeClaim>
                {
                    new ScopeClaim("role")
                }
            }
        };

        scopes.AddRange(StandardScopes.All);

        return scopes;
    }
}

改变在Startup.cs的factory类使用定义的scope

Factory = new IdentityServerServiceFactory()
    .UseInMemoryUsers(Users.Get())
    .UseInMemoryClients(Clients.Get())
    .UseInMemoryScopes(Scopes.Get()),

下一步我们为bob添加几个Claim

public static class Users
{
    public static IEnumerable<InMemoryUser> Get()
    {
        return new[]
        {
            new InMemoryUser
            {
                Username = "bob",
                Password = "secret",
                Subject = "1",

                Claims = new[]
                {
                    new Claim(Constants.ClaimTypes.GivenName, "Bob"),
                    new Claim(Constants.ClaimTypes.FamilyName, "Smith"),
                    new Claim(Constants.ClaimTypes.Role, "Geek"),
                    new Claim(Constants.ClaimTypes.Role, "Foo")
                }
            }
        };
    }
}

改变中间件配置:

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
    {
        Authority = "https://localhost:44319/identity",

        ClientId = "mvc",
        Scope = "openid profile roles",
        RedirectUri = "https://localhost:44319/",
        ResponseType = "id_token",

        SignInAsAuthenticationType = "Cookies"
    });

成功验证后,您现在应该看到用户Claim集合中的角色Claim

Claims 转换

默认情况下那些Claims看起像这样:

通过配置可以控制哪些claim需要被记录:

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
    {
        Authority = "https://localhost:44319/identity",

        ClientId = "mvc",
        Scope = "openid profile roles",
        RedirectUri = "https://localhost:44319/",
        ResponseType = "id_token",

        SignInAsAuthenticationType = "Cookies",
        UseTokenLifetime = false,

        Notifications = new OpenIdConnectAuthenticationNotifications
        {
            SecurityTokenValidated = async n =>
                {
                    var id = n.AuthenticationTicket.Identity;

                    // we want to keep first name, last name, subject and roles
                    var givenName = id.FindFirst(Constants.ClaimTypes.GivenName);
                    var familyName = id.FindFirst(Constants.ClaimTypes.FamilyName);
                    var sub = id.FindFirst(Constants.ClaimTypes.Subject);
                    var roles = id.FindAll(Constants.ClaimTypes.Role);

                    // create new identity and set name and role claim type
                    var nid = new ClaimsIdentity(
                        id.AuthenticationType,
                        Constants.ClaimTypes.GivenName,
                        Constants.ClaimTypes.Role);

                    nid.AddClaim(givenName);
                    nid.AddClaim(familyName);
                    nid.AddClaim(sub);
                    nid.AddClaims(roles);

                    // add some other app specific claim
                    nid.AddClaim(new Claim("app_specific", "some data"));                   

                    n.AuthenticationTicket = new AuthenticationTicket(
                        nid,
                        n.AuthenticationTicket.Properties);
                }
        }
    });

在添加上述代码后,我们的Claims现在看起来像这样:

Authorization

现在,我们有身份验证和一些声明,我们可以开始添加简单的授权规则。

MVC有一个内置的属性称为[Authorize]身份验证的用户,您还可以使用此属性来诠释角色成员资格要求。我们不建议这种方法,因为这通常会导致代码,混合的关注,如业务/控制器逻辑和授权政策。我们建议将授权逻辑从控制器中分离,从而导致更清洁的代码和更好的可测性(在  here 阅读更多)。

Resource Authorization

要添加新的授权基础设施和新的属性,我们添加NuGet包:

install-package Thinktecture.IdentityModel.Owin.ResourceAuthorization.Mvc
[ResourceAuthorize("Read", "ContactDetails")]
public ActionResult Contact()
{
    ViewBag.Message = "Your contact page.";

    return View();
}

请注意,属性是不表达权限,我们单独的逻辑去控制权限:

public class AuthorizationManager : ResourceAuthorizationManager
{
    public override Task<bool> CheckAccessAsync(ResourceAuthorizationContext context)
    {
        switch (context.Resource.First().Value)
        {
            case "ContactDetails":
                return AuthorizeContactDetails(context);
            default:
                return Nok();
        }
    }

    private Task<bool> AuthorizeContactDetails(ResourceAuthorizationContext context)
    {
        switch (context.Action.First().Value)
        {
            case "Read":
                return Eval(context.Principal.HasClaim("role", "Geek"));
            case "Write":
                return Eval(context.Principal.HasClaim("role", "Operator"));
            default:
                return Nok();
        }
    }
}

最后在Startup.cs中添加配置:

app.UseResourceAuthorization(new AuthorizationManager());

运行示例,并通过代码来熟悉验证的流程。

Role Authorization

通过重写AuthorizeAttribute控制返回的结果

// Customized authorization attribute:
public class AuthAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            // 403 we know who you are, but you haven‘t been granted access
            filterContext.Result = new HttpStatusCodeResult(System.Net.HttpStatusCode.Forbidden);
        }
        else
        {
            // 401 who are you? go login and then try again
            filterContext.Result = new HttpUnauthorizedResult();
        }
    }
}

// Usage:
[Auth(Roles = "Geek")]
public ActionResult About()
{
    // ...
}

其他的授权和处理访问被拒绝的情况

通过在HomeController中添加一个新的Action来进行更多的授权:

[ResourceAuthorize("Write", "ContactDetails")]
public ActionResult UpdateContact()
{
    ViewBag.Message = "Update your contact details!";

    return View();
}

当你试图访问这个地址的时候,你会看到一个被禁止的错误页面。

事实上,如果用户已经通过认证,你会看到不同的响应。如果不是MVC将重定向到登录页面,如果通过验证,您会看到禁止响应。这是由设计(阅读更多  here)。

你可以通过检查403个状态码来处理这个被禁止的情况,我们提供了一个这样的过滤框:

[ResourceAuthorize("Write", "ContactDetails")]
[HandleForbidden]
public ActionResult UpdateContact()
{
    ViewBag.Message = "Update your contact details!";

    return View();
}

添加HandleForbidden 后,看起是这样:

你也可以使用授权管理器势在必行,这给你更多的选择:

[HandleForbidden]
public ActionResult UpdateContact()
{
    if (!HttpContext.CheckAccess("Write", "ContactDetails", "some more data"))
    {
        // either 401 or 403 based on authentication state
        return this.AccessDenied();
    }

    ViewBag.Message = "Update your contact details!";
    return View();
}
时间: 2024-10-14 09:57:09

入门教程:.NET开源OpenID Connect 和OAuth解决方案IdentityServer v3 MVC认证与授权(四)的相关文章

IdentityServer3——入门教程:.NET开源OpenID Connect 和OAuth解决方案IdentityServer v3 术语

你应该知道的在文档和对象模型中使用一些特定的术语: OpenID Connect Provider (OP) 授权服务器 Thinktecture IdentityServer v3 是一个.NET 平台上开源的OpenID Connect 提供者 和 OAuth2 验证服务器,OpenID Connect Provider在不同的著作中有不同的说法,你可能发现有的叫安全令牌服务提供商,授权服务器,ip-sts和更多. 简单来说他们的共同点:为客户端提供一块安全令牌的软件. IdentitySe

一个功能完备的.NET开源OpenID Connect/OAuth 2.0框架&mdash;&mdash;IdentityServer3

今天推荐的是我一直以来都在关注的一个开源的OpenID Connect/OAuth 2.0服务框架--IdentityServer3.其支持完整的OpenID Connect/OAuth 2.0标准,使用它就可以轻易地搭建一个单点登录服务器. 说是一直关注,是因为1年前,要为一个平台搭建一个OAuth 2.0服务器,当时由于IdentityServer3还处于开发阶段,核心还不稳定,扩展功能也不完备.无奈只好熟读OAuth 2.0的规范,并根据www.asp.net网站上的一个简单示例自己实现了

OpenID Connect的常见问题与答案

OpenID Connect的常见问题与答案 OpenID Connect是什么,它是怎么样工作的? OpenID Connect是可互操作的身份验证协议基于OAuth 2.0规范族.它使用简单的REST / JSON消息流实现"让简单的事情变得简单和复杂的事情变为可能"的设计目标.开发者可以轻松集成.比较之前任何一种身份认证协议. OpenID Connect允许开发者验证跨网站和应用程序的用户,而无需拥有和管理密码文件.app builder,它提供了一个安全的可核查的,回答这个问

(译)OpenID Connect的常见问题与答案(二)

OpenID Connect是什么,它是怎么样工作的? OpenID Connect是可互操作的身份验证协议基于OAuth 2.0规范族.它使用简单的REST / JSON消息流实现“让简单的事情变得简单和复杂的事情变为可能”的设计目标.开发者可以轻松集成.比较之前任何一种身份认证协议. OpenID Connect允许开发者验证跨网站和应用程序的用户,而无需拥有和管理密码文件.app builder,它提供了一个安全的可核查的,回答这个问题:“当前需要身份验证的用户是使用浏览器还是本地应用 C

OpenID Connect Core 1.0(一)介绍

IdentityServer4是基于OpenID Connect and OAuth 2.0框架,OpenID Connect Core 1.0是IdentityServer4最重要的文档 By 道法自然  2018年 摘要 OpenID Connect Core 1.0是一个在OAuth 2.0 [RFC6749]协议之上简单的身份层.它使客户验证基于由授权服务器验证终端用户的身份,以及获得互操作的基本概要信息和终端用户REST-like方式. 这个规范定义了 OpenID Connect核心

OpenID Connect Core 1.0(九)声明(Claims)

5 声明(Claims) 这一节说明客户端如何获取关于终端用户声明和验证事件.它还定义了一组标准的基本声明配置.预定义一组可请求的声明,使用特定的scope值或能用于请求参数中的个人声明.声明可以直接来自OpenID提供者或分布式来源. 5.1 标准声明(Standard Claims) 这个规范定义了一组标准的声明.他们可以请求的返回或用户信息的响应,此在 5.3.2节或在第二节中的ID Token. sub string 在发行人终端用户的主体标识符. name  string 终端用户的全

.NET Core IdentityServer4实战 第二章-OpenID Connect添加用户认证

原文:.NET Core IdentityServer4实战 第二章-OpenID Connect添加用户认证 内容:本文带大家使用IdentityServer4进行使用OpenID Connect添加用户认证 作者:zara(张子浩) 欢迎分享,但需在文章鲜明处留下原文地址. 在这一篇文章中我们希望使用OpenID Connect这种方式来验证我们的MVC程序(需要有IdentityServer4),我们首先需要干什么呢?那就是搞一个UI,这样非常美观既可以看到我们的身份验证效果,那么Iden

IdentityServer3——入门教程:创建简单的OAuth2.0服务器,客户端和API

本教程的目的在于创造尽可能简单的identityserver安装作为一个oauth2授权服务器.这应该能够让你了解一些基本功能和配置选项(完整的源代码可以发现在这里).在后面的文档中会介绍更多的高级功能.本教程包括: 创建一个自托管identityserver 设置为使用一个应用程序的帐户以及用户对通信应用的客户服务代表 注册一个API 请求访问令牌 调用API 验证一个访问令牌 创建一个授权服务器(IdentityServer3) 创建一个控制台应用程序,并且在程序包管理器控制台中输入 ins

MVC入门教程

MVC入门系列教程-视频版本,已入驻51CTO学院,文本+视频学效果更好哦.视频链接地址如下: 点我查看视频.另外,针对该系列教程博主提供有偿技术支持,群号:226090960,群内会针对该教程的问题进行及时解答,公用性问题统一讲解.学习.NET MVC 只看在<无废话系列>足够了,<无废话系列>简单.快速.直接. 一.前言 以下是我自己写的MVC入门教程和一个外国人写的.觉得都很基础,够入门了.现整理成目录,先后顺序不代表排名. 二.我自己写的MVC入门教程 1.无废话MVC入门