IdentityServer4(五)

本文实现控制台应用程序连接IdentityServer服务端进行客户端验证,并调用授权API

1、新建控制台应用程序,nuget包安装 IdentityModel ,Program.cs代码如下:

class Program
    {
        static async Task Main(string[] args)
        {
            var client = new HttpClient();
            var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5001");
            if (disco.IsError)
            {
                Console.WriteLine(disco.Error);
                return;
            }

            //ClientId = "consoleclient",
            //        ClientName = "Client Credentials Client",

            //        AllowedGrantTypes = GrantTypes.ClientCredentials,
            //        ClientSecrets = { new Secret("consolesecret".Sha256()) },

            //        AllowedScopes = { "scope1" }

            var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
            {
                Address = disco.TokenEndpoint,

                ClientId = "consoleclient",
                ClientSecret = "consolesecret",
                Scope = "scope2"
            });

            if (tokenResponse.IsError)
            {
                Console.WriteLine(tokenResponse.Error);
                return;
            }

            Console.WriteLine(tokenResponse.Json);

            var apiClient = new HttpClient();
            apiClient.SetBearerToken(tokenResponse.AccessToken);

            var response = await apiClient.GetAsync("http://localhost:6001/identity");
            if (!response.IsSuccessStatusCode)
            {
                Console.WriteLine(response.StatusCode);
            }
            else
            {
                var content = await response.Content.ReadAsStringAsync();
                Console.WriteLine(JArray.Parse(content));
            }

            Console.ReadKey();
        }

    }

2、IdentityServer服务沿用前面文章所建的项目,并修改config文件。

 public static class Config
    {
        public static IEnumerable<IdentityResource> IdentityResources =>
            new IdentityResource[]
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile(),
            };

        public static IEnumerable<ApiScope> ApiScopes =>
            new ApiScope[]
            {
                new ApiScope("scope1"),
                new ApiScope("scope2"),
            };

        public static IEnumerable<Client> Clients =>
            new Client[]
            {
                // m2m client credentials flow client
                new Client
                {
                    ClientId = "consoleclient",
                    ClientName = "Client Credentials Client",

                    AllowedGrantTypes = GrantTypes.ClientCredentials,
                    ClientSecrets = { new Secret("consolesecret".Sha256()) },

                    AllowedScopes = { "scope1","scope2" }
                },

                   new Client
                {
                    ClientId = "wpfclient",
                    ClientName = "wpfclient Credentials",

                    AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
                    ClientSecrets = { new Secret("wpfsecret".Sha256()) },

                    AllowedScopes = { "scope1","scope2" }
                },

                // interactive client using code flow + pkce
                new Client
                {
                    ClientId = "interactive",
                    ClientSecrets = { new Secret("49C1A7E1-0C79-4A89-A3D6-A37998FB86B0".Sha256()) },

                    AllowedGrantTypes = GrantTypes.Code,

                    RedirectUris = { "https://localhost:44300/signin-oidc" },
                    FrontChannelLogoutUri = "https://localhost:44300/signout-oidc",
                    PostLogoutRedirectUris = { "https://localhost:44300/signout-callback-oidc" },

                    AllowOfflineAccess = true,
                    AllowedScopes = { "openid", "profile", "scope2" }
                },

                 new Client
                {
                    ClientId = "mvc",
                    ClientSecrets = { new Secret("secret".Sha256()) },
                
                    AllowedGrantTypes = GrantTypes.Code,
                
                    // where to redirect to after login
                    RedirectUris = { "http://localhost:5002/signin-oidc" },
                
                    // where to redirect to after logout
                    PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
                
                    AllowedScopes = new List<string>
                    {
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile
                    }
                }
            };
    }

3、新建Asp.net core API项目,nuget安装Microsoft.AspNetCore.Authentication.JwtBearer 包,修改Startup.cs文件。

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.AddControllers();

            services.AddAuthentication("Bearer")
           .AddJwtBearer("Bearer", options =>
           {
               options.Authority = "http://localhost:5001";
               options.RequireHttpsMetadata = false;
               options.TokenValidationParameters = new TokenValidationParameters
               {
                   ValidateAudience = false
               };
           });
            services.AddAuthorization(options =>
            {
                options.AddPolicy("ApiScope", policy =>
                {
                    policy.RequireAuthenticatedUser();
                    policy.RequireClaim("scope","scope2");
                });
            });
        }

        // 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();
            }

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                //.RequireAuthorization("ApiScope");
            });
        }
    }

4、Asp.net core API项目添加IdentityController.cs

  [Route("identity")]
    [Authorize("ApiScope")]
    public class IdentityController : ControllerBase
    {
        [HttpGet]
        public IActionResult Get()
        {
            return new JsonResult(
                from c in User.Claims
                select
                new
                {
                    c.Type,
                    c.Value
                }
                );
        }

    }

5、Asp.net core API项目添加NoScopeIdentityController.cs

 [Route("noscopeIdentity")]
    [ApiController]
    [Authorize]
    public class NoScopeIdentityController : ControllerBase
    {
        [HttpGet]
        public IActionResult Get()
        {
            return new JsonResult(
                from c in User.Claims
                select
                new
                {
                    c.Type,
                    c.Value
                }
                );
        }
    }

6.launchsettings.json

{
  
  "profiles": {
    "IdsWebApi": {
      "commandName": "Project",
      "dotnetRunMessages": "true",
      "launchBrowser": true,
      "launchUrl": "weatherforecast",
      "applicationUrl": "http://localhost:6001",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

7、添加wpf项目,Nuget安装 IdentitiModel 包

<Window x:Class="WpfClient.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfClient"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="40"></RowDefinition>
            <RowDefinition Height="40"></RowDefinition>
            <RowDefinition Height="40"></RowDefinition>
            <RowDefinition Height="40"></RowDefinition>
            <RowDefinition Height="40"></RowDefinition>
            <RowDefinition Height="40"></RowDefinition>
        </Grid.RowDefinitions>

        <StackPanel Orientation="Horizontal">
            <Label Content="账号"/>
            <TextBox Name="txtaccount" Width="100" Height="30"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Grid.Row="1">
            <Label Content="账号"/>
            <TextBox Name="txtpassword" Width="100" Height="30"/>
        </StackPanel>
        <Button Grid.Row="2"
                Height="30"
                Width="100"
                Content="登录"
                Click="Button_Click"/>
        
    </Grid>
</Window>
 public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Login();

        }

        public async Task Login()
        {
            var client = new HttpClient();
            var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5001");
            if (disco.IsError)
            {
                Console.WriteLine(disco.Error);
                return;
            }

            var token = await client.RequestPasswordTokenAsync(new PasswordTokenRequest
            {
                Address = disco.TokenEndpoint,
                UserName = txtaccount.Text,
                Password = txtpassword.Text,
                ClientId = "wpfclient",
                ClientSecret = "wpfsecret",
                Scope = "scope1"
            });
            if (token.IsError)
            {
                return;
            }
            Console.WriteLine(token.Json);

            var apiClient = new HttpClient();
            apiClient.SetBearerToken(token.AccessToken);

            var response = await apiClient.GetAsync("http://localhost:6001/noscopeIdentity");
            if (!response.IsSuccessStatusCode)
            {
                MessageBox.Show(response.StatusCode.ToString());
            }
            else
            {
                var content = await response.Content.ReadAsStringAsync();
                MessageBox.Show(content);
            }

        }
    }
原文地址:https://www.cnblogs.com/lhwpc/p/15076939.html