zoukankan      html  css  js  c++  java
  • 创建IdentityServer (3)

    该项目使用dotnet版本3.1 ,vs code创建

    创建Web MVC项目

    创建命令

    dotnet new mvc --name WebMvc
    

    修改./properties/launchSettings.json

    "profiles": {
        "WebApi": {
          "commandName": "Project",
          "launchBrowser": true,
          "launchUrl": "weatherforecast",
          "applicationUrl": "http://localhost:5002",
          "environmentVariables": {
            "ASPNETCORE_ENVIRONMENT": "Development"
          }
        }
      }
    

    添加登录验证

    运行下面命令安装

    dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer --version 3.1.0
    dotnet add package Microsoft.AspNetCore.Authentication.OpenIdConnect --version 3.1.0
    

    在startup.cs中的ConfigureServices类中添加

    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();     // 关闭了JWT的Claim 类型映射, 以便允许well-known claims.
    
    services.AddAuthentication(options =>   // 将身份验证服务添加到DI
        {
            options.DefaultScheme = "Cookies";      // 使用cookie来登录用户
            options.DefaultChallengeScheme = "oidc";        // 登录时使用OpenID Connect
        })
        .AddCookie("Cookies")
        .AddOpenIdConnect("oidc", options =>    // 配置执行OpenID Connect
        {
            options.Authority = "http://localhost:5000";    // IdentityServer地址
            options.RequireHttpsMetadata = false;       // 是否需要HTTPS
    
            options.ClientId = "mvc";
            options.SaveTokens = true;
        });
    

    在startup.cs中的Configure类中添加 认证中间件

    app.UseAuthentication();
    

    然后在HomeController中Privacy添加 Authorize属性

    然后AuthServer程序中的config.cs文件中将client修改如下

    new Client
    {
        ClientId = "mvc",
        ClientName = "MVC Client",
    
        AllowedGrantTypes = GrantTypes.Implicit,
        // AllowedGrantTypes = GrantTypes.CodeAndClientCredentials,
        // RequirePkce = true,
        // ClientSecrets = { new Secret("49C1A7E1-0C79-4A89-A3D6-A37998FB86B0".Sha256()) },
    
        RedirectUris = { "http://localhost:5002/signin-oidc" },     // login
        // FrontChannelLogoutUri = "http://localhost:5003/signout-oidc",       
        PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },     // logout
    
        AllowOfflineAccess = true,
        AllowedScopes = { "openid", "profile", "api1" }
    },
    

    在./view/home/Privacy.cshtml添加如下代码来显示登录成功的用户信息

    @using Microsoft.AspNetCore.Authentication
    <h2>Claims</h2>
    <div>
        <strong>id_token</strong>
        <span>@await ViewContext.HttpContext.GetTokenAsync("id_token")</span>
    </div>
    <div>
        <strong>access_token</strong>
        <span>@await ViewContext.HttpContext.GetTokenAsync("access_token")</span>
    </div>
    <dl>
        @foreach (var claim in User.Claims)
        {
            <dt>@claim.Type</dt>
            <dd>@claim.Value</dd>
        }
    </dl>
    

    开启AuthServer 和 WebMvc 程序,访问 http://localhost:5002/ ,点击 Privacy 会跳到AuthServer的登录页面

    输入账号 bob 密码 bob 后跳到如下页面

    点击YES后重定向返回 Privacy 页面,可以看到返回的信息,但access_token没有返回

    原因需要在上述修改的AuthServer文件中config的client加上

    AllowAccessTokensViaBrowser = true
    

    还要在WebMvc文件中的startup的 ConfigureServices 的 AddOpenIdConnect 加上

    options.ResponseType = "id_token token";
    

    重启两个程序,重新登录即可

    登出

    在HomeController类中添加

    public IActionResult Logout()
    {
        return SignOut("Cookies", "oidc");
    }
    

    在view/shared/_layout.cshtml添加

    <li class="nav-item">
         <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Logout">logout</a>
    </li>
    

    重启服务,登录后,点击logout,会跳到AuthServer的登出页面

    提供access token和refresh tokens来访问api

    使用refresh tokens来重新获取新的access token,确保会话不会断

    首先,将AuthServer项目的config文件中client修改如下

    new Client
    {
        ClientId = "mvc",
        ClientName = "MVC Client",
    
        AllowedGrantTypes = GrantTypes.Hybrid,      // GrantTypes.HybridAndClientCredentials 也可以
        ClientSecrets = { new Secret("secret".Sha256()) },
    
        RedirectUris = { "http://localhost:5002/signin-oidc" },        
        PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },   
    
        AllowOfflineAccess = true,
        AllowedScopes = { "openid", "profile", "api1" },
        AllowAccessTokensViaBrowser = true      
    },
    

    然后在WebMvc项目的startup文件中的ConfigureServices修改如下

    .AddOpenIdConnect("oidc", options =>    // 配置执行OpenID Connect
    {
        options.Authority = "http://localhost:5000";    // IdentityServer地址
        options.RequireHttpsMetadata = false;       // 是否需要HTTPS
        options.SignInScheme = "Cookies";
    
        options.ClientId = "mvc";
        options.SaveTokens = true;
        options.ResponseType = "id_token code";
        options.ClientSecret = "secret";
        options.GetClaimsFromUserInfoEndpoint = true;
    
        options.Scope.Add("api1");
        options.Scope.Add("offline_access");
    });
    

    在WebMvc项目view/home/privacy.cshtml中添加

    <div>
        <strong>refresh_token</strong>
        <span>@await ViewContext.HttpContext.GetTokenAsync("refresh_token")</span>
    </div>
    

    运行

    登录后,显示多出refresh_token

    打开postman使用refresh_token(注意:只能使用一次)来重新获取access token

    实现刷新Access Token

    首先安装IdentityModel
    dotnet add package IdentityModel --version 4.0.0

    在WebMvc的HomeController添加RefreshTokens()方法

    public async void RefreshTokensAsync()
    {
        var DiscoveryClient = new HttpClient();
        var diso = await DiscoveryClient.GetDiscoveryDocumentAsync("http://localhost:5000/");
        if (diso.IsError)
        {
            throw new Exception(diso.Error);
        }
        var refreshToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.RefreshToken);
        var response = await DiscoveryClient.RequestRefreshTokenAsync(new RefreshTokenRequest
        {
            Address = diso.TokenEndpoint,
            ClientId = "mvc",
            ClientSecret = "secret",
            Scope = "api1 openid profile ",
            GrantType = "refresh_token",
            RefreshToken = refreshToken
        });
        if (response.IsError)
        {
            throw new Exception(response.Error);
        }
    
        var expiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(response.ExpiresIn);
        var tokens = new[]
        {
            new AuthenticationToken
            {
                Name = OpenIdConnectParameterNames.IdToken,
                Value = response.IdentityToken
            },
            new AuthenticationToken
            {
                Name = OpenIdConnectParameterNames.AccessToken,
                Value = response.AccessToken
            },
            new AuthenticationToken
            {
                Name = OpenIdConnectParameterNames.RefreshToken,
                Value = response.RefreshToken
            },
            new AuthenticationToken
            {
                Name = "expires_at",
                Value = expiresAt.ToString("o", CultureInfo.InvariantCulture)
            }
        };
        var authenticationInfo = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);  // 等于Cookies
        authenticationInfo.Properties.StoreTokens(tokens);
        await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, authenticationInfo.Principal, authenticationInfo.Properties);
        // return response.AccessToken;
    }
    
    

  • 相关阅读:
    优化SQL查询:如何写出高性能SQL语句
    提高SQL执行效率的16种方法
    Spring Ioc DI 原理
    java内存泄漏
    转:js闭包
    LeetCode Best Time to Buy and Sell Stock III
    LeetCode Best Time to Buy and Sell Stock with Cooldown
    LeetCode Length of Longest Fibonacci Subsequence
    LeetCode Divisor Game
    LeetCode Sum of Even Numbers After Queries
  • 原文地址:https://www.cnblogs.com/hwxing/p/12780364.html
Copyright © 2011-2022 走看看