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;
    }
    
    

  • 相关阅读:
    入门activiti-------1简单运行
    JS对象、构造器函数和原型对象之间的关系
    myeclipse配背景色
    maven的pom.xml文件错误
    oracleXE简易版---使用基础
    ognl表达式注意事项
    Executors、ExecutorService、ThreadPoolExecutor
    ThreadPoolExecutor
    Phaser相位(工具的实战案例使用)
    ForkJoin
  • 原文地址:https://www.cnblogs.com/hwxing/p/12780364.html
Copyright © 2011-2022 走看看