方法一:
NuGet 引入包
IdentityServer4 3.1.4
IdentityServer4.EntityFramework 3.1.4
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.Relational
Microsoft.EntityFrameworkCore.Tools
Pomelo.EntityFrameworkCore.MySql 预发行版 5.0.0-alpha.2
下面直接贴代码
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.AddIdentityServer()
// //默认的开发者证书模式
// .AddDeveloperSigningCredential()
// //添加API资源作用域
// .AddInMemoryApiResources(IdentityConfig.IdentityConfig.GetApiScopes())
// //添加授权客户端
// .AddInMemoryClients(IdentityConfig.IdentityConfig.GetClients())
// //添加授权用户
// .AddTestUsers(IdentityConfig.IdentityConfig.GetTestUsers())
// //验证身份信息授权资源
// .AddInMemoryIdentityResources(IdentityConfig.IdentityConfig.IdentityResources)
// //解决 账户密码 模式 Claims 不携带的问题
// .AddProfileService<ProfileService>();
#region Identity Mysql
string connection = @"server=192.168.1.120;port=3306;database=IDS4;user=idsadmin;password=dev;";
//services.AddDbContext<DbContext>(options => options.UseMySQL(connection));
//services.AddDbContext<DbContext>(options => options.UseMySQL(GlobalAppConfig.myConfig.DbCon));
var builder = services.AddIdentityServer()
//身份信息资源
//.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddConfigurationStore(opt =>
{
opt.ConfigureDbContext = context =>
{
context.UseMySql(connection, ServerVersion.AutoDetect(connection), sql =>
{
sql.MigrationsAssembly("IDS4");
});
};
})
.AddOperationalStore(opt =>
{
opt.ConfigureDbContext = context =>
{
context.UseMySql(connection, ServerVersion.AutoDetect(connection), sql =>
{
sql.MigrationsAssembly("IDS4");
});
};
opt.EnableTokenCleanup = true;
opt.TokenCleanupInterval = 30;
})
.AddTestUsers(IdentityConfig.IdentityConfig.GetTestUsers());
#endregion
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "IDS4", Version = "v1" });
});
}
// 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.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "IDS4 v1"));
}
app.UseIdentityServer();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
ConsulHelper.ConsulRegist("http://192.168.1.234:8561/", "IDS4", "dev_dc", "192.168.1.162", 52838, 1);
}
}
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseUrls("http://*:52838");
webBuilder.UseStartup<Startup>();
});
}
public class IdentityConfig
{
/// <summary>
/// 验证资源--用户信息
/// </summary>
public static IEnumerable<IdentityResource> IdentityResources =>
new IdentityResource[]
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResource("TestResource","TestResource_DS",new List<string>{"Claim1","Claim2" })
};
/// <summary>
/// Authorization Server保护了哪些 API Scope(作用域)
/// </summary>
/// <returns></returns>
public static IEnumerable<ApiResource> GetApiScopes()
{
return new[] { new ApiResource("testApi") };
//return new[] { new ApiResource("testApi",new List<string> { "role" }) }; //自定义要传递的 Cliam
}
/// <summary>
/// 哪些客户端 Client(应用) 可以使用这个 Authorization Server
/// </summary>
/// <returns></returns>
public static IEnumerable<Client> GetClients()
{
return new[]
{
//账户密码模式
new Client()
{
//客户端的标识,要是惟一的
ClientId="TestPWD",
//客户端密码,进行了加密
ClientSecrets=new []{new Secret("123456".Sha256())},
//授权方式账户密码
AllowedGrantTypes= GrantTypes.ResourceOwnerPassword,
//定义这个客户端可以访问的APi资源数组
AllowedScopes=new[]{"testApi" },
//AlwaysIncludeUserClaimsInIdToken=true
},
//客户端模式
new Client()
{
//客户端的标识,要是惟一的
ClientId="TestClient",
//客户端密码,进行了加密
ClientSecrets=new []{new Secret("TestSecret".Sha256())},
//授权方式,这里采用的是客户端认证模式,只要ClientId,以及ClientSecrets正确即可访问对应的AllowedScopes里面的api资源
AllowedGrantTypes= GrantTypes.ClientCredentials,
//定义这个客户端可以访问的APi资源数组
AllowedScopes=new[]{"testApi" },
//携带的自定义信息
Claims=new List<Claim> {
new Claim(IdentityModel.JwtClaimTypes.Role,"DevClient"),
new Claim(IdentityModel.JwtClaimTypes.NickName,"TestDev")
}
},
隐藏模式----二次跳转
//new Client()
//{
// //客户端的标识,要是惟一的
// ClientId="TestImplicit",
// //客户端密码,进行了加密
// ClientSecrets=new []{new Secret("123456".Sha256())},
// //授权方式---隐藏模式
// AllowedGrantTypes= GrantTypes.Implicit,
// RedirectUris={ "http://192.168.1.162:60000/DevService01/api/Test2"},
// //定义这个客户端可以访问的APi资源数组
// AllowedScopes=new[]{"testApi" },
// //允许将Token通过浏览器传递
// AllowAccessTokensViaBrowser=true
//},
//授权码模式
//new Client()
//{
// //客户端的标识,要是惟一的
// ClientId="TestCode",
// //客户端密码,进行了加密
// ClientSecrets=new []{new Secret("123456".Sha256())},
// //授权方式---隐藏模式
// AllowedGrantTypes= GrantTypes.Code,
// RedirectUris={ "http://192.168.1.162:60000/DevService01/api/Test2"},
// //定义这个客户端可以访问的APi资源数组
// AllowedScopes=new[]{"testApi" },
// //允许将Token通过浏览器传递
// AllowAccessTokensViaBrowser=true
//},
//混合模式
new Client()
{
//客户端的标识,要是惟一的
ClientId="TestHybrid",
//客户端密码,进行了加密
ClientSecrets=new []{new Secret("123456".Sha256())},
//授权方式---隐藏模式
ClientName="TestHybrid ",
AllowedGrantTypes= GrantTypes.Hybrid,
IdentityTokenLifetime=3600,
//定义这个客户端可以访问的APi资源数组
//AllowedScopes=new[]{"testApi" },
AllowedScopes=new[]{"testApi",IdentityServerConstants.StandardScopes.OpenId,IdentityServerConstants.StandardScopes.Profile,"TestResource" },
//允许将Token通过浏览器传递
AllowAccessTokensViaBrowser=true
},
};
}
/// <summary>
/// 哪些User可以被这个AuthorizationServer识别并授权
/// </summary>
/// <returns></returns>
public static List<TestUser> GetTestUsers()
{
return new List<TestUser>
{
new TestUser
{
SubjectId="111",
Username="zx",
Password="123456",
IsActive=true,
Claims=new List<Claim> {
new Claim(IdentityModel.JwtClaimTypes.Role,"User"),
new Claim("Claim1","ClaimValue1"),
new Claim("Claim2","ClaimValue2"),
new Claim("Claim3","ClaimValue3"),
}
}
};
}
}
public class ProfileService : IProfileService
{
protected readonly TestUserStore Users;
public ProfileService(TestUserStore users)
{
Users = users;
}
public virtual Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var user = Users.FindBySubjectId(context.Subject.GetSubjectId());
if (user != null)
{
//context.IssuedClaims = user.Claims.ToList();
context.IssuedClaims.AddRange(user.Claims);
}
return Task.CompletedTask;
}
public async Task IsActiveAsync(IsActiveContext context)
{
await Task.Run(() =>
{
context.IsActive = true;
});
}
}
准备完毕后在程序包管理器控制台执行如下命令
EntityFrameworkCore\Add-Migration ConfigDbContext -c ConfigurationDbContext -o Data/Migrations/IdentityServer/PersistedGrantDb
EntityFrameworkCore\Update-Database -context ConfigurationDbContext
EntityFrameworkCore\Add-Migration OperationContext -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/OperationDb
EntityFrameworkCore\Update-Database -context PersistedGrantDbContext
方法二: 使用官方包 MySql.Data.EntityFrameworkCore 失败了
注意事项:
需要在MySQL 先执行创建CodeFirst记录表
CREATE TABLE `__EFMigrationsHistory` (
`MigrationId` varchar(150) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`ProductVersion` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
PRIMARY KEY (`MigrationId`)
)