• IdentityServer4 简单使用,包括api访问控制,openid的授权登录,js访问


    写在前面

    先分享一首数摇:http://music.163.com/m/song?id=36089751&userid=52749763

    其次是:对于identityServer理解并不是特别深刻,目前只是能简单的应用,里面一些具体设置以后可能慢慢更新到本文中。

    最后:一张大图


    IdentityServer4基于.net core的OAuth2.0和OpenId框架,主要应用于身份验证,单点登录,API访问控制等。。。

    IdentityServer4 文档: https://identityserver4.readthedocs.io/en/release/

    IdentityServer4 GitHub:https://github.com/IdentityServer/IdentityServer4/tree/dev/docs/topics

    本文demo:https://github.com/aspros-luo/IdentityServer4Demo

    api访问控制


    一.首先需要创建授权中心,

    新建.net core Web Application 项目,模板可以选择空或者web应用程序,偷懒的话直接选择web就好了

    1.在project.json里添加 "IdentityServer4": "1.0.0",nuget添加一样可以。

    2.我们需要新建一个配置文件configs.cs定义client和api作用域及账号信息具体代码如下:

    public static IEnumerable<ApiResource> GeyApiResources()
            {
                return new List<ApiResource>
                {
                    new ApiResource("UserApi","用户API")
                };
            }
            public static IEnumerable<Client> GetClients()
            {
                return new List<Client>
                {
                    new Client
                    {
                        ClientId = "Client",
                        AllowedGrantTypes = GrantTypes.ClientCredentials,
                        ClientSecrets =
                        {
                            new Secret("secret".Sha256())
                        },
                        AllowedScopes = {"UserApi"}
                    },
                    new Client
                    {
                        ClientId = "ro.Client",
                        AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
                        ClientSecrets =
                        {
                            new Secret("secret".Sha256())
                        },
                        AllowedScopes = {"UserApi"}
                    },
                       // OpenID Connect implicit flow client (MVC)
                    new Client
                    {
                        ClientId = "MVC",
                        ClientName = "MVC Client",
                        AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
                         ClientSecrets =
                        {
                            new Secret("secret".Sha256())
                        },
                        RedirectUris = { "http://localhost:5002/signin-oidc" },
                        PostLogoutRedirectUris = { "http://localhost:5002" },
    
                        AllowedScopes =
                        {
                            IdentityServerConstants.StandardScopes.OpenId,
                            IdentityServerConstants.StandardScopes.Profile,
                            "UserApi"
                        },
                        AllowOfflineAccess = true
                    },
                       // JavaScript Client
                    new Client
                    {
                        ClientId = "js",
                        ClientName = "JavaScript Client",
                        AllowedGrantTypes = GrantTypes.Implicit,
                        AllowAccessTokensViaBrowser = true,
    
                        RedirectUris = { "http://localhost:5003/callback.html" },
                        PostLogoutRedirectUris = { "http://localhost:5003/index.html" },
                        AllowedCorsOrigins = { "http://localhost:5003" },
    
                        AllowedScopes =
                        {
                            IdentityServerConstants.StandardScopes.OpenId,
                            IdentityServerConstants.StandardScopes.Profile,
                            "UserApi"
                        },
                    }
                };
            }
            public static List<TestUser> GeTestUsers()
            {
                return new List<TestUser>
                {
                    new TestUser
                    {
                        SubjectId = "1",
                        Username = "qwerty",
                        Password = "a123"
                    },
                    new TestUser
                    {
                        SubjectId = "2",
                        Username = "aspros",
                        Password = "b123"
                    }
                };
            }
    View Code

    3.在startup文件ConfigureServices里配置服务,Configure使用identityserver

     public void ConfigureServices(IServiceCollection services)
            {
                // Add framework services.
                services.AddApplicationInsightsTelemetry(Configuration);
                services.AddIdentityServer()
                    .AddTemporarySigningCredential()
                
                    .AddInMemoryApiResources(Configs.GeyApiResources())
                    .AddInMemoryClients(Configs.GetClients())
                    .AddTestUsers(Configs.GeTestUsers());
    
                services.AddMvc();
            }
    View Code
      public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
            {
                loggerFactory.AddConsole(Configuration.GetSection("Logging"));
                loggerFactory.AddDebug();
    
                app.UseApplicationInsightsRequestTelemetry();
    
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                    app.UseBrowserLink();
                }
                else
                {
                    app.UseExceptionHandler("/Home/Error");
                }
    
                app.UseApplicationInsightsExceptionTelemetry();
    
                app.UseStaticFiles();
    
    //使用userIdentityServer
                app.UseIdentityServer();
    
                app.UseMvc(routes =>
                {
                    routes.MapRoute(
                        name: "default",
                        template: "{controller=Home}/{action=Index}/{id?}");
                });
            }
    View Code

    4.更改当前应用程序的端口为:8000 (可略过)

    以上,基本授权中心配置完毕

    二.添加测试使用的api

    新建.net core Web Application,模板使用Api

    1.在project.json里添加  "IdentityServer4.AccessTokenValidation": "1.0.1", "Microsoft.AspNetCore.Cors": "1.1.0"(为跨域访问api做准备)

    2.在Startup文件里添加跨域服务,配置授权中心地址及scope api作用域

     public void ConfigureServices(IServiceCollection services)
            {
                // Add framework services.
                services.AddApplicationInsightsTelemetry(Configuration);
                #region 跨域
                services.AddCors(options =>
                {
                    // this defines a CORS policy called "default"
                    options.AddPolicy("default", policy =>
                    {
                        policy.WithOrigins("http://localhost:5003")
                            .AllowAnyHeader()
                            .AllowAnyMethod();
                    });
                });
                #endregion
                services.AddMvcCore()
                  .AddAuthorization()
                  .AddJsonFormatters();
            }
    View Code
     public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
            {
                loggerFactory.AddConsole(Configuration.GetSection("Logging"));
                loggerFactory.AddDebug();
                //配置identityServer授权
                app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
                {
                    Authority = "http://localhost:8000",
                    AllowedScopes = { "UserApi" },
                    RequireHttpsMetadata = false
                });
                //跨域访问
                app.UseCors("default");
    
                app.UseMvc();
            }
    View Code

    注释:cors可以暂时不配置,不影响后面调试

    3.在controller上添加   [Authorize]

      [Authorize]
        [Route("api/[controller]")]
        public class ValuesController : Controller
        {
            [HttpGet]
            public IActionResult Get()
            {
                //return Content("a");
                return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
            }
        }
    View Code

    4.更改api端口号,5001

    以上测试使用Api暂时配置完毕

    三.单元测试

    新建.net core 类库

    1.在project.json里添加

    "dotnet-test-xunit": "2.2.0-preview2-build1029",
    "IdentityModel": "2.1.1",
    "xunit": "2.2.0-beta4-build3444",
    "xunit.runner.console": "2.2.0-beta2-build3300"

    具体如下:

    {
      "version": "1.0.0-*",
      "testRunner": "xunit",
      "dependencies": {
        "dotnet-test-xunit": "2.2.0-preview2-build1029",
        "IdentityModel": "2.1.1",
        "xunit": "2.2.0-beta4-build3444",
        "xunit.runner.console": "2.2.0-beta2-build3300"
      },
    
      "frameworks": {
        "netcoreapp1.0.1": {
          "dependencies": {
            "Microsoft.NETCore.App": {
              "type": "platform",
              "version": "1.0.1"
            }
          }
        }
      }
    }
    View Code

    2.新建测试类,UserClientTest,代码如下

    public class UserClientTest
        {
            [Fact]
            public async Task ClientApiTest()
            {
                //get access_token
                var disco = await DiscoveryClient.GetAsync("http://localhost:8000");
                var tokenClient = new TokenClient(disco.TokenEndpoint, "Client", "secret");
                var tokenResponse = await tokenClient.RequestClientCredentialsAsync("UserApi");
    
                var client = new HttpClient();
                client.SetBearerToken(tokenResponse.AccessToken);//add bearer with access_token
                var response = await client.GetAsync("http://localhost:5001/api/Values");//call API with access_token
                var apiResult = response.Content.ReadAsStringAsync().Result;
                Assert.NotEmpty(apiResult);
            }
    
            [Fact]
            public async Task PasswordApiTests()
            {
                var disco = await DiscoveryClient.GetAsync("http://localhost:8000");
                var tokenClient = new TokenClient(disco.TokenEndpoint, "ro.Client", "secret");
                var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync("qwerty", "a123", "UserApi");
    
                var client = new HttpClient();
                client.SetBearerToken(tokenResponse.AccessToken);//add bearer with access_token
                var response = await client.GetAsync("http://localhost:5001/api/Values");//call API with access_token
                var apiResult = response.Content.ReadAsStringAsync().Result;
                Assert.NotEmpty(apiResult);
            }
    
        }
    View Code

    调试,

    1请求授权中心,带入clientId,secret,scope作用域(api) 得到access_token

    2得到access_token后,在header里添加Authorization:Bearer+access_token 请求api

    3返回结果


    OpenId 连接的mvc用户认证

    一.授权中心更改的地方:

    1.在授权中心里config里添加IdentityResource

       public static IEnumerable<IdentityResource> GetyIdentityResources()
            {
                return new List<IdentityResource>
                {
                    new IdentityResources.OpenId(),
                    new IdentityResources.Profile()
                };
            }
    View Code

    2.config=》client里添加mvc

     new Client
                    {
                        ClientId = "MVC",
                        ClientName = "MVC Client",
                        AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
                         ClientSecrets =
                        {
                            new Secret("secret".Sha256())
                        },
                        RedirectUris = { "http://localhost:5002/signin-oidc" },
                        PostLogoutRedirectUris = { "http://localhost:5002" },
    
                        AllowedScopes =
                        {
                            IdentityServerConstants.StandardScopes.OpenId,
                            IdentityServerConstants.StandardScopes.Profile,
                            "UserApi"
                        },
                        AllowOfflineAccess = true
                    },
    View Code

    (AllowedScopes 设置授权范围,加上“UserApi” 及AllowOfflineAccess = true 后,在授权中心登录验证通过后,显示对应访问权限)

    3.在startup里添加 AddInMemoryIdentityResources方法

     public void ConfigureServices(IServiceCollection services)
            {
                // Add framework services.
                services.AddApplicationInsightsTelemetry(Configuration);
                services.AddIdentityServer()
                    .AddTemporarySigningCredential()
                    .AddInMemoryApiResources(Configs.GeyApiResources())
                    .AddInMemoryClients(Configs.GetClients())
                    .AddInMemoryIdentityResources(Configs.GetyIdentityResources())
                    .AddTestUsers(Configs.GeTestUsers());
    
                services.AddMvc();
            }
    View Code

    (这里我出现过一个问题,在添加顺序的时候,将IdentityResources方法写在前面,单元测试请求api的时候会出现httpstatue 500错误)

    4.添加UI

    可以在github下载 https://github.com/IdentityServer/IdentityServer4.Quickstart.UI/tree/release

    (涉及到的页面及viewmodel较多。demo里我也重新整理过了)

    以上,授权中心部分修改完毕

    二.mvc客户端

    添加.net core web application 选择web应用程序

    1.在project.json 里添加

    "Microsoft.AspNetCore.Authentication.Cookies": "1.0.*",
    "Microsoft.AspNetCore.Authentication.OpenIdConnect": "1.0.*",
    "IdentityModel": "2.1.1"

    2.在startup里添加UseCookieAuthentication,UseOpenIdConnectAuthentication,代码如下

       public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
            {
                JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
    
                loggerFactory.AddConsole(Configuration.GetSection("Logging"));
                loggerFactory.AddDebug();
    
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    app.UseExceptionHandler("/Home/Error");
                }
    
                app.UseCookieAuthentication(new CookieAuthenticationOptions
                {
                    AuthenticationScheme = "Cookies"
                });
    
                app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
                {
                    AuthenticationScheme = "oidc",
                    SignInScheme = "Cookies",
    
                    Authority = "http://localhost:8000",
                    RequireHttpsMetadata = false,
    
                    ClientId = "MVC",
                    ClientSecret = "secret",
    
                    ResponseType = "code id_token",
                    Scope = { "UserApi", "offline_access" },//添加权限请求项
                    
                    GetClaimsFromUserInfoEndpoint = true,
                    SaveTokens = true
                });
    
                app.UseStaticFiles();
                app.UseMvcWithDefaultRoute();
            }
    View Code

    注意的地方,Authority为授权中心地址,ClientId与授权中心config里client里保持一致。Scope为请求权限项

    3.在action上加上[Authorize],启用授权

    4.更改端口为5002,可自行调节,需要与config保持一致

    使用:

    运行授权中心=》运行mvc客户端=》点击对应的授权的action链接=》跳转到授权中心登录页面=》输入账号密码后=》显示授权对应的权限列表=》跳回当前页面

    以上。


    js客户端访问

    js端访问配置稍微麻烦点,因为中间出了一些问题,主要是前端js功力不够,看的的时候比较吃力

    添加一个新项目。。先

    在mvc端中,我们引用了一个库处理openid连接,在javascript中也需要引用一个类似的库

    1.点击添加=》新建项=》左侧选择client-side选择NPM配置文件,默认为package.json

    在package.json 里添加"oidc-client": "1.2.2",如下

    {
      "version": "1.0.0",
      "name": "asp.net",
      "private": true,
      "devDependencies": {
        "oidc-client": "1.2.2"
      }
    }
    View Code

    找到oidc-client.js文件,将文件复制到wwwroot下(注意html页面引用就行) 

     

    2.添加两个html

    index.html

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8"/>
        <title></title>
    </head>
    <body>
        <button id="login">Login</button>
        <button id="api">Call API</button>
        <button id="logout">Logout</button>
    
        <pre id="results"></pre>
        <script src="http://code.jquery.com/jquery-latest.js"></script>
        <script src="oidc-client.js"></script>
        <script src="app.js"></script>
    </body>
    </html>
    View Code

    callBack.html

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        <script src="oidc-client.js"></script>
        <script>
            new Oidc.UserManager().signinRedirectCallback().then(function () {
                window.location = "index.html";
            }).catch(function (e) {
                console.error(e);
            });
        </script>
    </body>
    </html>
    View Code

    3.添加app.js

    /// <reference path="oidc-client.js" />
    
    function log() {
        document.getElementById('results').innerText = '';
    
        Array.prototype.forEach.call(arguments, function (msg) {
            if (msg instanceof Error) {
                msg = "Error: " + msg.message;
            }
            else if (typeof msg !== 'string') {
                msg = JSON.stringify(msg, null, 2);
            }
            document.getElementById('results').innerHTML += msg + '
    ';
        });
    }
    
    document.getElementById("login").addEventListener("click", login, false);
    document.getElementById("api").addEventListener("click", api, false);
    document.getElementById("logout").addEventListener("click", logout, false);
    
    var config = {
        authority: "http://localhost:8000",
        client_id: "js",
        redirect_uri: "http://localhost:5003/callback.html",
        response_type: "id_token token",
        scope: "openid profile UserApi",
        post_logout_redirect_uri: "http://localhost:5003/index.html",
    };
    var mgr = new Oidc.UserManager(config);
    
    mgr.getUser().then(function (user) {
        if (user) {
            log("User logged in", user.profile);
        }
        else {
            log("User not logged in");
        }
    });
    
    function login() {
        mgr.signinRedirect();
    }
    
    function api() {
        mgr.getUser().then(function (user) {
            var url = "http://localhost:5001/api/Values";
            var xhr = new XMLHttpRequest();
            xhr.open("GET", url);
            xhr.onload = function () {
                log(xhr.status, JSON.parse(xhr.responseText));
            }
            xhr.setRequestHeader("Authorization", "Bearer " + user.access_token);
            xhr.send();
        });
    }
    function logout() {
        mgr.signoutRedirect();
    }
    View Code

    4.将端口设为5003

    运行授权中心=》运行javascriptclient=》点击login=》跳转到授权中心登录页面=》登录后,显示权限列表=》返回5003

     以上


    更新

    看了昨天的评论,又去官方文档瞄了下,找到一些处理方法,如下

    https://identityserver4.readthedocs.io/en/release/quickstarts/8_entity_framework.html

    IdentityServer is designed for extensibility, and one of the extensibility points is the storage mechanism used for data that IdentityServer needs. This quickstart shows to how configure IdentityServer to use EntityFramework (EF) as the storage mechanism for this data (rather than using the in-memory implementations we had been using up until now).

    大概意思是说,可以用数据库存储apiresour,client和identityserverresource 资源

    新建或在原有的授权中心项目更改都是可以的,我这里是直接新建了一个

    1.在project.json里 dependencies添加

    "IdentityServer4.EntityFramework": "1.0.0",
    "Microsoft.EntityFrameworkCore.SqlServer": "1.1.0",
    "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",
    "Microsoft.EntityFrameworkCore.SqlServer.Design": "1.1.*"

    tools里添加(用于执行cmd的donet ef命令)

    "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final"

    2.新建config文件

    using System.Collections.Generic;
    using IdentityServer4;
    using IdentityServer4.Models;
    using IdentityServer4.Test;
    
    namespace EntityFrameworkDemo
    {
        public class Config
        {
            public static IEnumerable<IdentityResource> GetyIdentityResources()
            {
                return new List<IdentityResource>
                {
                    new IdentityResources.OpenId(),
                    new IdentityResources.Profile()
                };
            }
            public static IEnumerable<ApiResource> GeyApiResources()
            {
                return new List<ApiResource>
                {
                    new ApiResource("UserApi","用户API"),
                    new ApiResource("api1","测试api")
                };
            }
            public static IEnumerable<Client> GetClients()
            {
                return new List<Client>
                {
                    new Client
                    {
                        ClientId = "Client",
                        AllowedGrantTypes = GrantTypes.ClientCredentials,
                        ClientSecrets =
                        {
                            new Secret("secret".Sha256())
                        },
                        AllowedScopes = {"UserApi"}
                    },
                    new Client
                    {
                        ClientId = "ro.Client",
                        AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
                        ClientSecrets =
                        {
                            new Secret("secret".Sha256())
                        },
                        AllowedScopes = {"UserApi"}
                    },
                       // OpenID Connect implicit flow client (MVC)
                    new Client
                    {
                        ClientId = "MVC",
                        ClientName = "MVC Client",
                        AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
                         ClientSecrets =
                        {
                            new Secret("secret".Sha256())
                        },
                        RedirectUris = { "http://localhost:5002/signin-oidc" },
                        PostLogoutRedirectUris = { "http://localhost:5002" },
    
                        AllowedScopes =
                        {
                            IdentityServerConstants.StandardScopes.OpenId,
                            IdentityServerConstants.StandardScopes.Profile,
                            "UserApi"
                        },
                        AllowOfflineAccess = true
                    },
                       // JavaScript Client
                    new Client
                    {
                        ClientId = "js",
                        ClientName = "JavaScript Client",
                        AllowedGrantTypes = GrantTypes.Implicit,
                        AllowAccessTokensViaBrowser = true,
    
                        RedirectUris = { "http://localhost:5003/callback.html" },
                        PostLogoutRedirectUris = { "http://localhost:5003/index.html" },
                        AllowedCorsOrigins = { "http://localhost:5003" },
    
                        AllowedScopes =
                        {
                            IdentityServerConstants.StandardScopes.OpenId,
                            IdentityServerConstants.StandardScopes.Profile,
                            "UserApi"
                        },
                    }
                };
            }
            public static List<TestUser> GetTestUsers()
            {
                return new List<TestUser>
                {
                    new TestUser
                    {
                        SubjectId = "1",
                        Username = "qwerty",
                        Password = "a123"
                    },
                    new TestUser
                    {
                        SubjectId = "2",
                        Username = "aspros",
                        Password = "b123"
                    }
                };
            }
        }
    }
    View Code

    3.在startup里添加对应的服务

    (1).修改ConfigureServices

    旧:ConfigureServices里如下

         services.AddIdentityServer()
                    .AddTemporarySigningCredential()
                    .AddInMemoryApiResources(Configs.GeyApiResources())
                    .AddInMemoryClients(Configs.GetClients())
                    .AddInMemoryIdentityResources(Configs.GetyIdentityResources())
                    .AddTestUsers(Configs.GeTestUsers());
    View Code

    新:ConfigureServices里如下

     var connectionString = @"server=.;database=IdentityServer4;trusted_connection=yes";
                var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
    
                // configure identity server with in-memory users, but EF stores for clients and resources
                services.AddIdentityServer()
                    .AddTemporarySigningCredential()
                    .AddTestUsers(Config.GetTestUsers())
                    .AddConfigurationStore(builder =>
                        builder.UseSqlServer(connectionString, options =>
                            options.MigrationsAssembly(migrationsAssembly)))
                    .AddOperationalStore(builder =>
                        builder.UseSqlServer(connectionString, options =>
                            options.MigrationsAssembly(migrationsAssembly)));
    View Code

    (2).修改Configure

      app.UseIdentityServer();
    
                app.UseCookieAuthentication(new CookieAuthenticationOptions
                {
                    AuthenticationScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme,
    
                    AutomaticAuthenticate = false,
                    AutomaticChallenge = false
                });
    View Code

    (3).初始化数据库

       private void InitializeDatabase(IApplicationBuilder app)
            {
                using (var scope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
                {
                    scope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();
    
                    var context = scope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
                    context.Database.Migrate();
    
                    if (!context.Clients.Any())
                    {
                        foreach (var client in Config.GetClients().Where(client => !context.Clients.Any(c => c.ClientId == client.ClientId)))
                        {
                            context.Clients.Add(client.ToEntity());
                        }
                    }
    
                    //context.SaveChanges();
    
                    if (!context.IdentityResources.Any())
                    {
                        foreach (
                            var identity in
                                Config.GetyIdentityResources()
                                    .Where(identity => !context.IdentityResources.Any(i => i.Name == identity.Name)))
                        {
                            context.IdentityResources.Add(identity.ToEntity());
                        }
                    }
                    //context.SaveChanges();
                    if (!context.ApiResources.Any())
                    {
                        foreach (var api in Config.GeyApiResources().Where(api => !context.ApiResources.Any(a => a.Name == api.Name)))
                        {
                            context.ApiResources.Add(api.ToEntity());
                        }
                    }
    
                    context.SaveChanges();
                }
            }
    View Code

    在Configure添加初始化数据库方法

      public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
            {
                // this will do the initial DB population
                InitializeDatabase(app);
                ...
             }        
    View Code

    4.在当前项目目录,如 G:MyProjectIdentityServerDemosrcEntityFrameworkDemo下shift+右键,在此处打开命令窗口,运行下面两行命令

    dotnet ef migrations add InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrantDb
    dotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/ConfigurationDb
     

    5.重新运行授权中心前更改端口号为8001(如果是新建的项目),在sqlserver数据库会生成对应的数据库

    6.将api的授权地址改成8001

    7.运行单元测试

    以上

    如有问题,欢迎指正。

  • 相关阅读:
    css单行排版
    sass安装(windows版)
    php通过post将表单数据保存到数据库实例
    C#-socket简单同步通信学习
    让VS变成彩色码
    VS项目启动后 提示ID为*******的进程当前未运行
    C#实现简单验证码
    API清理xml格式数据
    VS提示-无法启动IIS Express Web服务器-的解决方法
    C#MVC中ztree的简单使用
  • 原文地址:https://www.cnblogs.com/AsprosL/p/6232678.html
Copyright © 2020-2023  润新知