Skip to content

Commit 714ffb9

Browse files
committed
Merge branch 'dev' into main
2 parents 0941550 + a9b8589 commit 714ffb9

File tree

8 files changed

+170
-3
lines changed

8 files changed

+170
-3
lines changed

src/Meowv.Blog.Api/appsettings.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,9 @@ authorize:
7070
clientId: '3725213942'
7171
clientSecret: ''
7272
redirectUrl: 'https://admin.meowv.com/oauth/weibo'
73-
scope: 'all'
73+
scope: 'all'
74+
qq:
75+
clientId: '101935194'
76+
clientSecret: ''
77+
redirectUrl: 'https://admin.meowv.com/oauth/qq'
78+
scope: 'get_user_info'

src/Meowv.Blog.Application/Authorize/Impl/AuthorizeService.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public class AuthorizeService : ServiceBase, IAuthorizeService
3333
private readonly OAuthDingtalkService _dingtalkService;
3434
private readonly OAuthMicrosoftService _microsoftService;
3535
private readonly OAuthWeiboService _weiboService;
36+
private readonly OAuthQQService _qqService;
3637

3738
public AuthorizeService(IOptions<JwtOptions> jwtOption,
3839
IToolService toolService,
@@ -43,7 +44,8 @@ public AuthorizeService(IOptions<JwtOptions> jwtOption,
4344
OAuthAlipayService alipayService,
4445
OAuthDingtalkService dingtalkService,
4546
OAuthMicrosoftService microsoftService,
46-
OAuthWeiboService weiboService)
47+
OAuthWeiboService weiboService,
48+
OAuthQQService qqService)
4749
{
4850
_jwtOption = jwtOption.Value;
4951
_toolService = toolService;
@@ -55,6 +57,7 @@ public AuthorizeService(IOptions<JwtOptions> jwtOption,
5557
_dingtalkService = dingtalkService;
5658
_microsoftService = microsoftService;
5759
_weiboService = weiboService;
60+
_qqService = qqService;
5861
}
5962

6063
/// <summary>
@@ -77,6 +80,7 @@ public async Task<BlogResponse<string>> GetAuthorizeUrlAsync(string type)
7780
"dingtalk" => await _dingtalkService.GetAuthorizeUrl(state),
7881
"microsoft" => await _microsoftService.GetAuthorizeUrl(state),
7982
"weibo" => await _weiboService.GetAuthorizeUrl(state),
83+
"qq" => await _qqService.GetAuthorizeUrl(state),
8084
_ => throw new NotImplementedException($"Not implemented:{type}")
8185
}
8286
};
@@ -113,6 +117,7 @@ public async Task<BlogResponse<string>> GenerateTokenAsync(string type, string c
113117
"dingtalk" => GenerateToken(await _dingtalkService.GetUserByOAuthAsync(type, code, state)),
114118
"microsoft" => GenerateToken(await _microsoftService.GetUserByOAuthAsync(type, code, state)),
115119
"weibo" => GenerateToken(await _weiboService.GetUserByOAuthAsync(type, code, state)),
120+
"qq" => GenerateToken(await _qqService.GetUserByOAuthAsync(type, code, state)),
116121
_ => throw new NotImplementedException($"Not implemented:{type}")
117122
};
118123

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using Meowv.Blog.Domain.Users;
2+
using Meowv.Blog.Dto.Authorize;
3+
using Meowv.Blog.Extensions;
4+
using Meowv.Blog.Options.Authorize;
5+
using System.Collections.Generic;
6+
using System.Net.Http;
7+
using System.Threading.Tasks;
8+
using System.Web;
9+
10+
namespace Meowv.Blog.Authorize.OAuth.Impl
11+
{
12+
public class OAuthQQService : OAuthServiceBase<QQOptions, AccessTokenBase, QQUserInfo>
13+
{
14+
public override async Task<string> GetAuthorizeUrl(string state)
15+
{
16+
var param = BuildAuthorizeUrlParams(state);
17+
var url = $"{Options.Value.AuthorizeUrl}?{param.ToQueryString()}";
18+
19+
return await Task.FromResult(url);
20+
}
21+
22+
public override async Task<User> GetUserByOAuthAsync(string type, string code, string state)
23+
{
24+
var accessToken = await GetAccessTokenAsync(code, state);
25+
var userInfo = await GetUserInfoAsync(accessToken);
26+
27+
return await UserService.CreateUserAsync(userInfo.Name, type, userInfo.Id, userInfo.Name, userInfo.Avatar, userInfo.Email);
28+
}
29+
30+
public override async Task<AccessTokenBase> GetAccessTokenAsync(string code, string state)
31+
{
32+
var param = BuildAccessTokenParams(code, state);
33+
Options.Value.AccessTokenUrl = $"{Options.Value.AccessTokenUrl}?{param.ToQueryString()}";
34+
35+
using var client = HttpClient.CreateClient();
36+
var response = await client.GetStringAsync(Options.Value.AccessTokenUrl);
37+
38+
var qscoll = HttpUtility.ParseQueryString(response);
39+
40+
return new AccessTokenBase
41+
{
42+
AccessToken = qscoll["access_token"]
43+
};
44+
}
45+
46+
public override async Task<QQUserInfo> GetUserInfoAsync(AccessTokenBase accessToken)
47+
{
48+
using var client = HttpClient.CreateClient();
49+
50+
var openIdResponse = await client.GetStringAsync($"{Options.Value.OpenIdUrl}?access_token={accessToken.AccessToken}&fmt=json");
51+
var openId = openIdResponse.DeserializeToObject<QQOpenId>().OpenId;
52+
53+
var param = BuildUserInfoParams(accessToken.AccessToken, openId);
54+
Options.Value.UserInfoUrl = $"{Options.Value.UserInfoUrl}?{param.ToQueryString()}";
55+
56+
var response = await client.GetStringAsync(Options.Value.UserInfoUrl);
57+
58+
var userInfo = response.DeserializeToObject<QQUserInfo>();
59+
userInfo.Id = openId;
60+
61+
return userInfo;
62+
}
63+
64+
protected Dictionary<string, string> BuildAuthorizeUrlParams(string state)
65+
{
66+
return new Dictionary<string, string>
67+
{
68+
["client_id"] = Options.Value.ClientId,
69+
["response_type"] = "code",
70+
["redirect_uri"] = Options.Value.RedirectUrl,
71+
["scope"] = Options.Value.Scope,
72+
["state"] = state
73+
};
74+
}
75+
76+
protected Dictionary<string, string> BuildAccessTokenParams(string code, string state)
77+
{
78+
return new Dictionary<string, string>()
79+
{
80+
["client_id"] = Options.Value.ClientId,
81+
["client_secret"] = Options.Value.ClientSecret,
82+
["grant_type"] = "authorization_code",
83+
["redirect_uri"] = Options.Value.RedirectUrl,
84+
["code"] = code,
85+
["state"] = state
86+
};
87+
}
88+
89+
protected Dictionary<string, string> BuildUserInfoParams(string accessToken, string openId)
90+
{
91+
return new Dictionary<string, string>()
92+
{
93+
["access_token"] = accessToken,
94+
["oauth_consumer_key"] = Options.Value.ClientId,
95+
["openid"] = openId,
96+
};
97+
}
98+
}
99+
}

src/Meowv.Blog.Application/Users/Impl/UserService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ public async Task<BlogResponse<UserDto>> GetCurrentUserAsync()
220220
[RemoteService(false)]
221221
public async Task<User> CreateUserAsync(string username, string type, string identity, string name, string avatar, string email)
222222
{
223-
var user = await _users.FindAsync(x => x.Username == username && x.Type == type && x.Identity == identity);
223+
var user = await _users.FindAsync(x => x.Type == type && x.Identity == identity);
224224
if (user is null)
225225
{
226226
await _users.InsertAsync(new User

src/Meowv.Blog.Core/MeowvBlogCoreModule.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ public override void PreConfigureServices(ServiceConfigurationContext context)
116116
var dingtalkOption = authorizeOption.GetSection("dingtalk");
117117
var microsoftOption = authorizeOption.GetSection("microsoft");
118118
var weiboOptions = authorizeOption.GetSection("weibo");
119+
var qqOptions = authorizeOption.GetSection("qq");
119120

120121
Configure<AuthorizeOptions>(authorizeOption);
121122
Configure<GithubOptions>(githubOption);
@@ -124,6 +125,7 @@ public override void PreConfigureServices(ServiceConfigurationContext context)
124125
Configure<DingtalkOptions>(dingtalkOption);
125126
Configure<MicrosoftOptions>(microsoftOption);
126127
Configure<WeiboOptions>(weiboOptions);
128+
Configure<QQOptions>(qqOptions);
127129

128130
options.Github = new GithubOptions
129131
{
@@ -168,6 +170,13 @@ public override void PreConfigureServices(ServiceConfigurationContext context)
168170
RedirectUrl = weiboOptions.GetValue<string>(nameof(options.Weibo.RedirectUrl)),
169171
Scope = weiboOptions.GetValue<string>(nameof(options.Weibo.Scope))
170172
};
173+
options.QQ = new QQOptions
174+
{
175+
ClientId = qqOptions.GetValue<string>(nameof(options.QQ.ClientId)),
176+
ClientSecret = qqOptions.GetValue<string>(nameof(options.QQ.ClientSecret)),
177+
RedirectUrl = qqOptions.GetValue<string>(nameof(options.QQ.RedirectUrl)),
178+
Scope = qqOptions.GetValue<string>(nameof(options.QQ.Scope))
179+
};
171180

172181
authorize = options;
173182
});
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
namespace Meowv.Blog.Options.Authorize
2+
{
3+
public class QQOptions
4+
{
5+
public string ClientId { get; set; }
6+
7+
public string ClientSecret { get; set; }
8+
9+
public string RedirectUrl { get; set; }
10+
11+
public string Scope { get; set; }
12+
13+
public string AuthorizeUrl = "https://graph.qq.com/oauth2.0/authorize";
14+
15+
public string AccessTokenUrl = "https://graph.qq.com/oauth2.0/token";
16+
17+
public string OpenIdUrl = "https://graph.qq.com/oauth2.0/me";
18+
19+
public string UserInfoUrl = "https://graph.qq.com/user/get_user_info";
20+
}
21+
}

src/Meowv.Blog.Core/Options/AuthorizeOptions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,10 @@ public class AuthorizeOptions
3333
/// Weibo
3434
/// </summary>
3535
public WeiboOptions Weibo { get; set; }
36+
37+
/// <summary>
38+
/// QQ
39+
/// </summary>
40+
public QQOptions QQ { get; set; }
3641
}
3742
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using Newtonsoft.Json;
2+
3+
namespace Meowv.Blog.Dto.Authorize
4+
{
5+
public class QQUserInfo
6+
{
7+
public string Id { get; set; }
8+
9+
[JsonProperty("nickname")]
10+
public string Name { get; set; }
11+
12+
[JsonProperty("figureurl_qq")]
13+
public string Avatar { get; set; }
14+
15+
public string Email { get; set; } = "";
16+
}
17+
18+
public class QQOpenId
19+
{
20+
[JsonProperty("openid")]
21+
public string OpenId { get; set; }
22+
}
23+
}

0 commit comments

Comments
 (0)