diff --git a/src/OSharp/Core/Options/OAuth2Options.cs b/src/OSharp/Core/Options/OAuth2Options.cs new file mode 100644 index 000000000..8a4913ba0 --- /dev/null +++ b/src/OSharp/Core/Options/OAuth2Options.cs @@ -0,0 +1,32 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) 2014-2019 OSharp. All rights reserved. +// +// http://www.osharp.org +// 郭明锋 +// 2019-03-31 18:18 +// ----------------------------------------------------------------------- + +namespace OSharp.Core.Options +{ + /// + /// 第三方OAuth2登录的配置选项 + /// + public class OAuth2Options + { + /// + /// 获取或设置 本应用在第三方OAuth2系统中的客户端Id + /// + public string ClientId { get; set; } + + /// + /// 获取或设置 本应用在第三方OAuth2系统中的客户端密钥 + /// + public string ClientSecret { get; set; } + + /// + /// 获取或设置 是否启用 + /// + public bool Enabled { get; set; } + } +} \ No newline at end of file diff --git a/src/OSharp/Core/Options/OSharpOptions.cs b/src/OSharp/Core/Options/OSharpOptions.cs index deb09a6c6..1a2461051 100644 --- a/src/OSharp/Core/Options/OSharpOptions.cs +++ b/src/OSharp/Core/Options/OSharpOptions.cs @@ -26,6 +26,7 @@ public class OsharpOptions public OsharpOptions() { DbContexts = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + OAuth2S = new ConcurrentDictionary(); } /// @@ -33,6 +34,11 @@ public OsharpOptions() /// public IDictionary DbContexts { get; } + /// + /// 获取 第三方OAuth2登录配置信息 + /// + public IDictionary OAuth2S { get; } + /// /// 获取或设置 邮件发送选项 /// diff --git a/src/OSharp/Core/Options/OSharpOptionsSetup.cs b/src/OSharp/Core/Options/OSharpOptionsSetup.cs index 171eb64a3..5637bb086 100644 --- a/src/OSharp/Core/Options/OSharpOptionsSetup.cs +++ b/src/OSharp/Core/Options/OSharpOptionsSetup.cs @@ -40,8 +40,20 @@ public void Configure(OsharpOptions options) { SetDbContextOptionses(options); + IConfigurationSection section; + //OAuth2 + section = _configuration.GetSection("OSharp:OAuth2"); + IDictionary dict = section.Get>(); + if (dict != null) + { + foreach (KeyValuePair item in dict) + { + options.OAuth2S.Add(item.Key, item.Value); + } + } + //MailSender - IConfigurationSection section = _configuration.GetSection("OSharp:MailSender"); + section = _configuration.GetSection("OSharp:MailSender"); MailSenderOptions sender = section.Get(); if (sender != null) { diff --git a/tests/web/Liuliu.Demo.Core/Identity/IdentityPack.cs b/tests/web/Liuliu.Demo.Core/Identity/IdentityPack.cs index 6ffa1a812..c0064361e 100644 --- a/tests/web/Liuliu.Demo.Core/Identity/IdentityPack.cs +++ b/tests/web/Liuliu.Demo.Core/Identity/IdentityPack.cs @@ -8,6 +8,7 @@ // ----------------------------------------------------------------------- using System; +using System.Collections.Generic; using System.ComponentModel; using System.Text; using System.Threading.Tasks; @@ -23,6 +24,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; +using OSharp.Core.Options; using OSharp.Exceptions; using OSharp.Extensions; using OSharp.Identity; @@ -104,16 +106,16 @@ protected override void AddAuthentication(IServiceCollection services) options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(jwt => { - string secret = configuration["Authentication:Jwt:Secret"]; + string secret = configuration["OSharp:Jwt:Secret"]; if (secret.IsNullOrEmpty()) { - throw new OsharpException("配置文件中Authentication配置的Jwt节点的Secret不能为空"); + throw new OsharpException("配置文件中OSharp配置的Jwt节点的Secret不能为空"); } jwt.TokenValidationParameters = new TokenValidationParameters() { - ValidIssuer = configuration["Authentication:Jwt:Issuer"]?? "osharp identity", - ValidAudience = configuration["Authentication:Jwt:Audience"]?? "osharp client", + ValidIssuer = configuration["OSharp:Jwt:Issuer"] ?? "osharp identity", + ValidAudience = configuration["OSharp:Jwt:Audience"] ?? "osharp client", IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secret)), LifetimeValidator = (before, expires, token, param) => expires > DateTime.Now, ValidateLifetime = true @@ -138,44 +140,53 @@ protected override void AddAuthentication(IServiceCollection services) }; }); - bool enabled = configuration["Authentication:QQ:Enabled"].CastTo(false); - if (enabled) + // OAuth2 + IConfigurationSection section = configuration.GetSection("OSharp:OAuth2"); + IDictionary dict = section.Get>(); + if (dict == null) { - string appId = configuration["Authentication:QQ:AppId"]; - if (string.IsNullOrEmpty(appId)) + return; + } + foreach (KeyValuePair pair in dict) + { + OAuth2Options value = pair.Value; + if (!value.Enabled) { - throw new OsharpException("配置文件中Authentication配置的QQ节点的AppId不能为空"); + continue; } - string appKey = configuration["Authentication:QQ:AppKey"]; - if (string.IsNullOrEmpty(appKey)) + if (string.IsNullOrEmpty(value.ClientId)) { - throw new OsharpException("配置文件中Authentication配置的QQ节点的AppKey不能为空"); + throw new OsharpException($"配置文件中OSharp:OAuth2配置的{pair.Key}节点的ClientId不能为空"); } - authenticationBuilder.AddQQ(qq => - { - qq.AppId = appId; - qq.AppKey = appKey; - }); - } - - enabled = configuration["Authentication:Microsoft:Enabled"].CastTo(false); - if (enabled) - { - string clientId = configuration["Authentication:Microsoft:ClientId"]; - if (string.IsNullOrEmpty(clientId)) + if (string.IsNullOrEmpty(value.ClientSecret)) { - throw new OsharpException("配置文件中Authentication配置的Microsoft节点的ClientId不能为空"); + throw new OsharpException($"配置文件中OSharp:OAuth2配置的{pair.Key}节点的ClientSecret不能为空"); } - string clientSecret = configuration["Authentication:Microsoft:ClientSecret"]; - if (string.IsNullOrEmpty(clientSecret)) + + switch (pair.Key) { - throw new OsharpException("配置文件中Authentication配置的Microsoft节点的ClientSecret不能为空"); + case "QQ": + authenticationBuilder.AddQQ(opts => + { + opts.AppId = value.ClientId; + opts.AppKey = value.ClientSecret; + }); + break; + case "Microsoft": + authenticationBuilder.AddMicrosoftAccount(opts => + { + opts.ClientId = value.ClientId; + opts.ClientSecret = value.ClientSecret; + }); + break; + case "GitHub": + authenticationBuilder.AddGitHub(opts => + { + opts.ClientId = value.ClientId; + opts.ClientSecret = value.ClientSecret; + }); + break; } - authenticationBuilder.AddMicrosoftAccount(ms => - { - ms.ClientId = clientId; - ms.ClientSecret = clientSecret; - }); } } diff --git a/tests/web/Liuliu.Demo.Core/Liuliu.Demo.Core.csproj b/tests/web/Liuliu.Demo.Core/Liuliu.Demo.Core.csproj index 30e2a5dfb..138faa7fc 100644 --- a/tests/web/Liuliu.Demo.Core/Liuliu.Demo.Core.csproj +++ b/tests/web/Liuliu.Demo.Core/Liuliu.Demo.Core.csproj @@ -11,6 +11,7 @@ + diff --git a/tests/web/Liuliu.Demo.Web/appsettings.Development.json b/tests/web/Liuliu.Demo.Web/appsettings.Development.json index 799b402fe..9e961ea2b 100644 --- a/tests/web/Liuliu.Demo.Web/appsettings.Development.json +++ b/tests/web/Liuliu.Demo.Web/appsettings.Development.json @@ -1,24 +1,4 @@ { - //"ConnectionStrings": { - // "DefaultDbContext": "Server=.;Database=osharpns.demo.webapi3;Trusted_Connection=True;MultipleActiveResultSets=true" - //}, - "Authentication": { - "Jwt": { - "Issuer": "osharp identity", - "Audience": "osharp angular demo", - "Secret": "{8619F7C3-B53C-4B85-99F0-983D351ECD82}" - }, - "QQ": { - "AppId": "你的QQ互联项目AppId", - "AppKey": "你的QQ互联项目AppKey", - "Enabled": false - }, - "Microsoft": { - "ClientId": "你的微软项目ClientId", - "ClientSecret": "你的微软项目ClientSecret", - "Enabled": false - } - }, "Logging": { "IncludeScopes": true, "LogLevel": { @@ -67,6 +47,33 @@ // "AutoMigrationEnabled": true //} }, + "OAuth2": { + //"QQ": { + // "ClientId": "你的QQ互联项目AppId", + // "ClientSecret": "你的QQ互联项目AppKey", + // "Enabled": false + //}, + //"Microsoft": { + // "ClientId": "你的微软项目ClientId", + // "ClientSecret": "你的微软项目ClientSecret", + // "Enabled": false + //}, + //"GitHub": { + // "ClientId": "你的微软项目ClientId", + // "ClientSecret": "你的微软项目ClientSecret", + // "Enabled": false + //} + }, + "Logging": { + "IncludeScopes": true, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Warning", + "OSharp": "Debug", + "Liuliu": "Debug" + } + }, "MailSender": { "Host": "smtp.66soft.net", "DisplayName": "柳柳发件测试", diff --git a/tests/web/Liuliu.Demo.Web/appsettings.json b/tests/web/Liuliu.Demo.Web/appsettings.json index 698d4e70e..7986790ee 100644 --- a/tests/web/Liuliu.Demo.Web/appsettings.json +++ b/tests/web/Liuliu.Demo.Web/appsettings.json @@ -1,7 +1,4 @@ { - "ConnectionStrings": { - "DefaultDbContext": "Server=.;Database=osharp.demo.webapi;User Id=test;Password=abcd123456;MultipleActiveResultSets=true" - }, "Logging": { "IncludeScopes": true, "LogLevel": { diff --git a/tests/web/ui/ng-alain7/package-lock.json b/tests/web/ui/ng-alain7/package-lock.json index 2279f90df..647189736 100644 --- a/tests/web/ui/ng-alain7/package-lock.json +++ b/tests/web/ui/ng-alain7/package-lock.json @@ -1,6 +1,6 @@ { "name": "osharpns", - "version": "0.4.7", + "version": "0.5.0-beta01", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/tests/web/ui/ng-alain7/package.json b/tests/web/ui/ng-alain7/package.json index 15939e653..b14d9063c 100644 --- a/tests/web/ui/ng-alain7/package.json +++ b/tests/web/ui/ng-alain7/package.json @@ -1,6 +1,6 @@ { "name": "osharpns", - "version": "0.4.7", + "version": "0.5.0-beta01", "scripts": { "ng": "ng", "start": "npm run color-less && ng serve -o --port 4201 --proxy-config proxy.config.json", diff --git a/tests/web/ui/ng-alain7/src/app/layout/default/header/components/user.component.ts b/tests/web/ui/ng-alain7/src/app/layout/default/header/components/user.component.ts index c0b554d19..f7a75d8c8 100644 --- a/tests/web/ui/ng-alain7/src/app/layout/default/header/components/user.component.ts +++ b/tests/web/ui/ng-alain7/src/app/layout/default/header/components/user.component.ts @@ -2,6 +2,7 @@ import { Component, Inject, ChangeDetectionStrategy } from '@angular/core'; import { Router } from '@angular/router'; import { SettingsService } from '@delon/theme'; import { DA_SERVICE_TOKEN, ITokenService } from '@delon/auth'; +import { IdentityService } from '@shared/osharp/services/identity.service'; @Component({ selector: 'header-user', @@ -34,11 +35,14 @@ export class HeaderUserComponent { constructor( public settings: SettingsService, private router: Router, + private identity: IdentityService, @Inject(DA_SERVICE_TOKEN) private tokenService: ITokenService, ) { } logout() { - this.tokenService.clear(); - this.router.navigateByUrl(this.tokenService.login_url); + this.identity.logout().then(res => { + this.tokenService.clear(); + this.router.navigateByUrl(this.tokenService.login_url); + }); } } diff --git a/tests/web/ui/ng-alain7/src/app/layout/default/header/header.component.html b/tests/web/ui/ng-alain7/src/app/layout/default/header/header.component.html index 104b17120..814a48a60 100644 --- a/tests/web/ui/ng-alain7/src/app/layout/default/header/header.component.html +++ b/tests/web/ui/ng-alain7/src/app/layout/default/header/header.component.html @@ -1,7 +1,7 @@
diff --git a/tests/web/ui/ng-alain7/src/app/layout/passport/passport.component.html b/tests/web/ui/ng-alain7/src/app/layout/passport/passport.component.html index 6cb253fee..dc3e836c8 100644 --- a/tests/web/ui/ng-alain7/src/app/layout/passport/passport.component.html +++ b/tests/web/ui/ng-alain7/src/app/layout/passport/passport.component.html @@ -3,8 +3,8 @@
- - ng-alain + + osharp
武林中最有影响力的《葵花宝典》;欲练神功,挥刀自宫
diff --git a/tests/web/ui/ng-alain7/src/app/routes/exception/exception-routing.module.ts b/tests/web/ui/ng-alain7/src/app/routes/exception/exception-routing.module.ts index 1e7195458..e9d41d2d3 100644 --- a/tests/web/ui/ng-alain7/src/app/routes/exception/exception-routing.module.ts +++ b/tests/web/ui/ng-alain7/src/app/routes/exception/exception-routing.module.ts @@ -7,9 +7,9 @@ import { Exception500Component } from './500.component'; import { ExceptionTriggerComponent } from './trigger.component'; const routes: Routes = [ - { path: '403', component: Exception403Component }, - { path: '404', component: Exception404Component }, - { path: '500', component: Exception500Component }, + { path: '403', component: Exception403Component, data: { title: '403' } }, + { path: '404', component: Exception404Component, data: { title: '404' } }, + { path: '500', component: Exception500Component, data: { title: '500' } }, { path: 'trigger', component: ExceptionTriggerComponent }, ]; @@ -17,4 +17,4 @@ const routes: Routes = [ imports: [RouterModule.forChild(routes)], exports: [RouterModule], }) -export class ExceptionRoutingModule {} +export class ExceptionRoutingModule { } diff --git a/tests/web/ui/ng-alain7/src/app/routes/passport/login/login.component.html b/tests/web/ui/ng-alain7/src/app/routes/passport/login/login.component.html index 8243dd4be..523da62e2 100644 --- a/tests/web/ui/ng-alain7/src/app/routes/passport/login/login.component.html +++ b/tests/web/ui/ng-alain7/src/app/routes/passport/login/login.component.html @@ -81,5 +81,6 @@ {{ 'app.login.sign-in-with' | translate }} + {{ 'app.login.signup' | translate }}
diff --git a/tests/web/ui/ng-alain7/src/app/routes/profile/edit/edit.component.ts b/tests/web/ui/ng-alain7/src/app/routes/profile/edit/edit.component.ts index 87a71793b..3e433fe5a 100644 --- a/tests/web/ui/ng-alain7/src/app/routes/profile/edit/edit.component.ts +++ b/tests/web/ui/ng-alain7/src/app/routes/profile/edit/edit.component.ts @@ -22,7 +22,7 @@ export class ProfileEditComponent implements OnInit { ngOnInit() { let user = this.settings.user; - let userNameEdit = ['QQ_', 'Microsoft_'].some(m => user.name.startsWith(m)); + let userNameEdit = ['QQ_', 'Microsoft_', 'GitHub_'].some(m => user.name.startsWith(m)); this.headImgUrl = user.avatar; this.schema = { properties: { diff --git a/tests/web/ui/ng-alain7/src/app/routes/profile/oauth2/oauth2.component.html b/tests/web/ui/ng-alain7/src/app/routes/profile/oauth2/oauth2.component.html index f3bc5374c..673fc385e 100644 --- a/tests/web/ui/ng-alain7/src/app/routes/profile/oauth2/oauth2.component.html +++ b/tests/web/ui/ng-alain7/src/app/routes/profile/oauth2/oauth2.component.html @@ -1,4 +1,4 @@
- +
diff --git a/tests/web/ui/ng-alain7/src/app/routes/routes.routing.ts b/tests/web/ui/ng-alain7/src/app/routes/routes.routing.ts index 96e3ecc9d..6f74db76f 100644 --- a/tests/web/ui/ng-alain7/src/app/routes/routes.routing.ts +++ b/tests/web/ui/ng-alain7/src/app/routes/routes.routing.ts @@ -10,12 +10,13 @@ import { DashboardComponent } from './dashboard/dashboard.component'; // single pages import { CallbackComponent } from './callback/callback.component'; import { ACLGuard } from '@delon/acl'; +import { SimpleGuard } from '@delon/auth'; const routes: Routes = [ { path: '', component: LayoutDefaultComponent, - canActivate: [], + canActivate: [SimpleGuard], data: { title: '主页' }, children: [ { path: '', redirectTo: 'dashboard', pathMatch: 'full' }, diff --git a/tests/web/ui/ng-alain7/src/app/shared/components/modal-tree/modal-tree.component.ts b/tests/web/ui/ng-alain7/src/app/shared/components/modal-tree/modal-tree.component.ts index 8ee807aec..9b9ce1153 100644 --- a/tests/web/ui/ng-alain7/src/app/shared/components/modal-tree/modal-tree.component.ts +++ b/tests/web/ui/ng-alain7/src/app/shared/components/modal-tree/modal-tree.component.ts @@ -30,7 +30,7 @@ export class ModalTreeComponent { constructor(public http: _HttpClient, private alain: AlainService) { } - private loadTreeData() { + loadTreeData() { let url = this.treeDataUrl; if (!url) { return; diff --git a/tests/web/ui/ng-alain7/src/app/shared/osharp/services/identity.service.ts b/tests/web/ui/ng-alain7/src/app/shared/osharp/services/identity.service.ts index 4069502d1..e448c9d6c 100644 --- a/tests/web/ui/ng-alain7/src/app/shared/osharp/services/identity.service.ts +++ b/tests/web/ui/ng-alain7/src/app/shared/osharp/services/identity.service.ts @@ -88,6 +88,7 @@ export class IdentityService { this.tokenSrv.set({ token }); } else { this.tokenSrv.clear(); + this.settingSrv.setUser({}); } // 刷新用户信息 return this.refreshUser(); diff --git a/tests/web/ui/ng-alain7/src/assets/osharp/logo-color.svg b/tests/web/ui/ng-alain7/src/assets/osharp/logo-color.svg new file mode 100644 index 000000000..bc4022f26 --- /dev/null +++ b/tests/web/ui/ng-alain7/src/assets/osharp/logo-color.svg @@ -0,0 +1,17 @@ + + + + + 背景 + + + + Layer 1 + + + + + + + + diff --git a/tests/web/ui/ng-alain7/src/assets/osharp/logo-full.svg b/tests/web/ui/ng-alain7/src/assets/osharp/logo-full.svg new file mode 100644 index 000000000..d6018a786 --- /dev/null +++ b/tests/web/ui/ng-alain7/src/assets/osharp/logo-full.svg @@ -0,0 +1,21 @@ + + + + 背景 + + + + + logo + + + + + + + + + text + sharp + + diff --git a/tests/web/ui/ng-alain7/src/assets/osharp/logo.svg b/tests/web/ui/ng-alain7/src/assets/osharp/logo.svg new file mode 100644 index 000000000..211275662 --- /dev/null +++ b/tests/web/ui/ng-alain7/src/assets/osharp/logo.svg @@ -0,0 +1,17 @@ + + + + + 背景 + + + + Layer 1 + + + + + + + +