版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
【移動(dòng)應(yīng)用開發(fā)技術(shù)】ASP.NETCore集成微信登錄的示例分析
工具:1準(zhǔn)備工作1.1配置接口信息/upload/information/20201208/260/10251.jpg1.2修改網(wǎng)頁(yè)授權(quán)信息/upload/information/20201208/260/10252.jpg/upload/information/20201208/260/10253.jpg2新建網(wǎng)站項(xiàng)目2.1選擇ASP.NETCoreWebApplication模板/upload/information/20201208/260/10254.jpg2.2選擇Web應(yīng)用程序,并更改身份驗(yàn)證為個(gè)人用戶賬戶/upload/information/20201208/260/10255.jpg3集成微信登錄功能3.1添加引用/upload/information/20201208/260/10256.jpg3.2添加代碼文件/upload/information/20201208/260/10257.jpg3.3注冊(cè)微信登錄中間件app.UseWeChatAuthentication(new
WeChatOptions()
{
AppId
=
"******",
AppSecret
=
"******"
});/upload/information/20201208/260/10258.jpg4代碼//
Copyright
(c)
.NET
Foundation.
All
rights
reserved.
//
Licensed
under
the
Apache
License,
Version
2.0.
See
License.txt
in
the
project
root
for
license
information.
using
System;
using
Microsoft.AspNetCore.Authentication.WeChat;
using
Microsoft.Extensions.Options;
namespace
Microsoft.AspNetCore.Builder
{
///
<summary>
///
Extension
methods
to
add
authentication
capabilities
to
an
HTTP
application
pipeline.
///
</summary>
public
static
class
WeChatAppBuilderExtensions
{
///
<summary>
///
Adds
the
<see
cref="WeChatMiddleware"/>
middleware
to
the
specified
<see
cref="IApplicationBuilder"/>,
which
enables
authentication
capabilities.
///
</summary>
///
<param
name="app">The
<see
cref="IApplicationBuilder"/>
to
add
the
middleware
to.</param>
///
<returns>A
reference
to
this
instance
after
the
operation
has
completed.</returns>
public
static
IApplicationBuilder
UseWeChatAuthentication(this
IApplicationBuilder
app)
{
if
(app
==
null)
{
throw
new
ArgumentNullException(nameof(app));
}
return
app.UseMiddleware<WeChatMiddleware>();
}
///
<summary>
///
Adds
the
<see
cref="WeChatMiddleware"/>
middleware
to
the
specified
<see
cref="IApplicationBuilder"/>,
which
enables
authentication
capabilities.
///
</summary>
///
<param
name="app">The
<see
cref="IApplicationBuilder"/>
to
add
the
middleware
to.</param>
///
<param
name="options">A
<see
cref="WeChatOptions"/>
that
specifies
options
for
the
middleware.</param>
///
<returns>A
reference
to
this
instance
after
the
operation
has
completed.</returns>
public
static
IApplicationBuilder
UseWeChatAuthentication(this
IApplicationBuilder
app,
WeChatOptions
options)
{
if
(app
==
null)
{
throw
new
ArgumentNullException(nameof(app));
}
if
(options
==
null)
{
throw
new
ArgumentNullException(nameof(options));
}
return
app.UseMiddleware<WeChatMiddleware>(Options.Create(options));
}
}
}//
Copyright
(c)
.NET
Foundation.
All
rights
reserved.
//
Licensed
under
the
Apache
License,
Version
2.0.
See
License.txt
in
the
project
root
for
license
information.
namespace
Microsoft.AspNetCore.Authentication.WeChat
{
public
static
class
WeChatDefaults
{
public
const
string
AuthenticationScheme
=
"WeChat";
public
static
readonly
string
AuthorizationEndpoint
=
"/connect/oauth3/authorize";
public
static
readonly
string
TokenEndpoint
=
"/sns/oauth3/access_token";
public
static
readonly
string
UserInformationEndpoint
=
"/sns/userinfo";
}
}//
Copyright
(c)
.NET
Foundation.
All
rights
reserved.
//
Licensed
under
the
Apache
License,
Version
2.0.
See
License.txt
in
the
project
root
for
license
information.
using
Microsoft.AspNetCore.Authentication.OAuth;
using
Microsoft.AspNetCore.Builder;
using
Microsoft.AspNetCore.Http.Authentication;
using
Microsoft.AspNetCore.Http.Extensions;
using
Microsoft.Extensions.Primitives;
using
Newtonsoft.Json.Linq;
using
System;
using
System.Collections.Generic;
using
System.Net.Http;
using
System.Net.Http.Headers;
using
System.Security.Claims;
using
System.Text;
using
Microsoft.AspNetCore.Mvc;
using
System.Threading.Tasks;
namespace
Microsoft.AspNetCore.Authentication.WeChat
{
internal
class
WeChatHandler
:
OAuthHandler<WeChatOptions>
{
public
WeChatHandler(HttpClient
httpClient)
:
base(httpClient)
{
}
protected
override
async
Task<AuthenticateResult>
HandleRemoteAuthenticateAsync()
{
AuthenticationProperties
properties
=
null;
var
query
=
Request.Query;
var
error
=
query["error"];
if
(!StringValues.IsNullOrEmpty(error))
{
var
failureMessage
=
new
StringBuilder();
failureMessage.Append(error);
var
errorDescription
=
query["error_description"];
if
(!StringValues.IsNullOrEmpty(errorDescription))
{
failureMessage.Append(";Description=").Append(errorDescription);
}
var
errorUri
=
query["error_uri"];
if
(!StringValues.IsNullOrEmpty(errorUri))
{
failureMessage.Append(";Uri=").Append(errorUri);
}
return
AuthenticateResult.Fail(failureMessage.ToString());
}
var
code
=
query["code"];
var
state
=
query["state"];
var
oauthState
=
query["oauthstate"];
properties
=
Options.StateDataFormat.Unprotect(oauthState);
if
(state
!=
Options.StateAddition
||
properties
==
null)
{
return
AuthenticateResult.Fail("The
oauth
state
was
missing
or
invalid.");
}
//
OAuth3
10.12
CSRF
if
(!ValidateCorrelationId(properties))
{
return
AuthenticateResult.Fail("Correlation
failed.");
}
if
(StringValues.IsNullOrEmpty(code))
{
return
AuthenticateResult.Fail("Code
was
not
found.");
}
//獲取tokens
var
tokens
=
await
ExchangeCodeAsync(code,
BuildRedirectUri(Options.CallbackPath));
var
identity
=
new
ClaimsIdentity(Options.ClaimsIssuer);
AuthenticationTicket
ticket
=
null;
if
(Options.WeChatScope
==
Options.InfoScope)
{
//獲取用戶信息
ticket
=
await
CreateTicketAsync(identity,
properties,
tokens);
}
else
{
//不獲取信息,只使用openid
identity.AddClaim(new
Claim(ClaimTypes.NameIdentifier,
tokens.TokenType,
ClaimValueTypes.String,
Options.ClaimsIssuer));
ticket
=
new
AuthenticationTicket(new
ClaimsPrincipal(identity),
properties,
Options.AuthenticationScheme);
}
if
(ticket
!=
null)
{
return
AuthenticateResult.Success(ticket);
}
else
{
return
AuthenticateResult.Fail("Failed
to
retrieve
user
information
from
remote
server.");
}
}
///
<summary>
///
OAuth第一步,獲取code
///
</summary>
///
<param
name="properties"></param>
///
<param
name="redirectUri"></param>
///
<returns></returns>
protected
override
string
BuildChallengeUrl(AuthenticationProperties
properties,
string
redirectUri)
{
//加密OAuth狀態(tài)
var
oauthstate
=
Options.StateDataFormat.Protect(properties);
//
redirectUri
=
$"{redirectUri}?{nameof(oauthstate)}={oauthstate}";
var
queryBuilder
=
new
QueryBuilder()
{
{
"appid",
Options.ClientId
},
{
"redirect_uri",
redirectUri
},
{
"response_type",
"code"
},
{
"scope",
Options.WeChatScope
},
{
"state",
Options.StateAddition
},
};
return
Options.AuthorizationEndpoint
+
queryBuilder.ToString();
}
///
<summary>
///
OAuth第二步,獲取token
///
</summary>
///
<param
name="code"></param>
///
<param
name="redirectUri"></param>
///
<returns></returns>
protected
override
async
Task<OAuthTokenResponse>
ExchangeCodeAsync(string
code,
string
redirectUri)
{
var
tokenRequestParameters
=
new
Dictionary<string,
string>()
{
{
"appid",
Options.ClientId
},
{
"secret",
Options.ClientSecret
},
{
"code",
code
},
{
"grant_type",
"authorization_code"
},
};
var
requestContent
=
new
FormUrlEncodedContent(tokenRequestParameters);
var
requestMessage
=
new
HttpRequestMessage(HttpMethod.Post,
Options.TokenEndpoint);
requestMessage.Headers.Accept.Add(new
MediaTypeWithQualityHeaderValue("application/json"));
requestMessage.Content
=
requestContent;
var
response
=
await
Backchannel.SendAsync(requestMessage,
Context.RequestAborted);
if
(response.IsSuccessStatusCode)
{
var
payload
=
JObject.Parse(await
response.Content.ReadAsStringAsync());
string
ErrCode
=
payload.Value<string>("errcode");
string
ErrMsg
=
payload.Value<string>("errmsg");
if
(!string.IsNullOrEmpty(ErrCode)
|
!string.IsNullOrEmpty(ErrMsg))
{
return
OAuthTokenResponse.Failed(new
Exception($"ErrCode:{ErrCode},ErrMsg:{ErrMsg}"));
}
var
tokens
=
OAuthTokenResponse.Success(payload);
//借用TokenType屬性保存openid
tokens.TokenType
=
payload.Value<string>("openid");
return
tokens;
}
else
{
var
error
=
"OAuth
token
endpoint
failure";
return
OAuthTokenResponse.Failed(new
Exception(error));
}
}
///
<summary>
///
OAuth第四步,獲取用戶信息
///
</summary>
///
<param
name="identity"></param>
///
<param
name="properties"></param>
///
<param
name="tokens"></param>
///
<returns></returns>
protected
override
async
Task<AuthenticationTicket>
CreateTicketAsync(ClaimsIdentity
identity,
AuthenticationProperties
properties,
OAuthTokenResponse
tokens)
{
var
queryBuilder
=
new
QueryBuilder()
{
{
"access_token",
tokens.AccessToken
},
{
"openid",
tokens.TokenType
},//在第二步中,openid被存入TokenType屬性
{
"lang",
"zh_CN"
}
};
var
infoRequest
=
Options.UserInformationEndpoint
+
queryBuilder.ToString();
var
response
=
await
Backchannel.GetAsync(infoRequest,
Context.RequestAborted);
if
(!response.IsSuccessStatusCode)
{
throw
new
HttpRequestException($"Failed
to
retrieve
user
information
({response.StatusCode})
Please
check
if
the
authentication
information
is
correct
and
the
corresponding
Graph
API
is
enabled.");
}
var
user
=
JObject.Parse(await
response.Content.ReadAsStringAsync());
var
ticket
=
new
AuthenticationTicket(new
ClaimsPrincipal(identity),
properties,
Options.AuthenticationScheme);
var
context
=
new
OAuthCreatingTicketContext(ticket,
Context,
Options,
Backchannel,
tokens,
user);
var
identifier
=
user.Value<string>("openid");
if
(!string.IsNullOrEmpty(identifier))
{
identity.AddClaim(new
Claim(ClaimTypes.NameIdentifier,
identifier,
ClaimValueTypes.String,
Options.ClaimsIssuer));
}
var
nickname
=
user.Value<string>("nickname");
if
(!string.IsNullOrEmpty(nickname))
{
identity.AddClaim(new
Claim(ClaimTypes.Name,
nickname,
ClaimValueTypes.String,
Options.ClaimsIssuer));
}
var
sex
=
user.Value<string>("sex");
if
(!string.IsNullOrEmpty(sex))
{
identity.AddClaim(new
Claim("urn:WeChat:sex",
sex,
ClaimValueTypes.String,
Options.ClaimsIssuer));
}
var
country
=
user.Value<string>("country");
if
(!string.IsNullOrEmpty(country))
{
identity.AddClaim(new
Claim(ClaimTypes.Country,
country,
ClaimValueTypes.String,
Options.ClaimsIssuer));
}
var
province
=
user.Value<string>("province");
if
(!string.IsNullOrEmpty(province))
{
identity.AddClaim(new
Claim(ClaimTypes.StateOrProvince,
province,
ClaimValueTypes.String,
Options.ClaimsIssuer));
}
var
city
=
user.Value<string>("city");
if
(!string.IsNullOrEmpty(city))
{
identity.AddClaim(new
Claim("urn:WeChat:city",
city,
ClaimValueTypes.String,
Options.ClaimsIssuer));
}
var
headimgurl
=
user.Value<string>("headimgurl");
if
(!string.IsNullOrEmpty(headimgurl))
{
identity.AddClaim(new
Claim("urn:WeChat:headimgurl",
headimgurl,
ClaimValueTypes.String,
Options.ClaimsIssuer));
}
var
unionid
=
user.Value<string>("unionid");
if
(!string.IsNullOrEmpty(unionid))
{
identity.AddClaim(new
Claim("urn:WeChat:unionid",
unionid,
ClaimValueTypes.String,
Options.ClaimsIssuer));
}
await
Options.Events.CreatingTicket(context);
return
context.Ticket;
}
}
}//
Copyright
(c)
.NET
Foundation.
All
rights
reserved.
//
Licensed
under
the
Apache
License,
Version
2.0.
See
License.txt
in
the
project
root
for
license
information.
using
System;
using
System.Globalization;
using
System.Text.Encodings.Web;
using
Microsoft.AspNetCore.Authentication.OAuth;
using
Microsoft.AspNetCore.Builder;
using
Microsoft.AspNetCore.DataProtection;
using
Microsoft.AspNetCore.Http;
using
Microsoft.Extensions.Logging;
using
Microsoft.Extensions.Options;
namespace
Microsoft.AspNetCore.Authentication.WeChat
{
///
<summary>
///
An
ASP.NET
Core
middleware
for
authenticating
users
using
WeChat.
///
</summary>
public
class
WeChatMiddleware
:
OAuthMiddleware<WeChatOptions>
{
///
<summary>
///
Initializes
a
new
<see
cref="WeChatMiddleware"/>.
///
</summary>
///
<param
name="next">The
next
middleware
in
the
HTTP
pipeline
to
invoke.</param>
///
<param
name="dataProtectionProvider"></param>
///
<param
name="loggerFactory"></param>
///
<param
name="encoder"></param>
///
<param
name="sharedOptions"></param>
///
<param
name="options">Configuration
options
for
the
middleware.</param>
public
WeChatMiddleware(
RequestDelegate
next,
IDataProtectionProvider
dataProtectionProvider,
ILoggerFactory
loggerFactory,
UrlEncoder
encoder,
IOptions<SharedAuthenticationOptions>
sharedOptions,
IOptions<WeChatOptions>
options)
:
base(next,
dataProtectionProvider,
loggerFactory,
encoder,
sharedOptions,
options)
{
if
(next
==
null)
{
throw
new
ArgumentNullException(nameof(next));
}
if
(dataProtectionProvider
==
null)
{
throw
new
ArgumentNullException(nameof(dataProtectionProvider));
}
if
(loggerFactory
==
null)
{
throw
new
ArgumentNullException(nameof(loggerFactory));
}
if
(encoder
==
null)
{
throw
new
ArgumentNullException(nameof(encoder));
}
if
(sharedOptions
==
null)
{
throw
new
ArgumentNullException(nameof(sharedOptions));
}
if
(options
==
null)
{
throw
new
ArgumentNullException(nameof(options));
}
if
(string.IsNullOrEmpty(Options.AppId))
{
throw
new
ArgumentException(string.Format(CultureInfo.CurrentCulture,
nameof(Options.AppId)));
}
if
(string.IsNullOrEmpty(Options.AppSecret))
{
throw
new
ArgumentException(string.Format(CultureInfo.CurrentCulture,
nameof(Options.AppSecret)));
}
}
///
<summary>
///
Provides
the
<see
cref="AuthenticationHandler{T}"/>
object
for
processing
authentication-related
requests.
///
</summary>
///
<returns>An
<see
cref="AuthenticationHandler{T}"/>
configured
with
the
<see
cref="WeChatOptions"/>
supplied
to
the
constructor.</returns>
protected
override
AuthenticationHandler<WeChatOptions>
CreateHandler()
{
return
new
WeChatHandler(Backchannel);
}
}
}//
Copyright
(c)
.NET
Foundation.
All
rights
reserved.
//
Licensed
under
the
Apache
License,
Version
2.0.
See
License.txt
in
the
project
root
for
license
information.
using
System.Collections.Generic;
using
Micr
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 北京經(jīng)貿(mào)職業(yè)學(xué)院《中國(guó)古代文學(xué)史(3)》2023-2024學(xué)年第一學(xué)期期末試卷
- 2025年度智能安防系統(tǒng)項(xiàng)目監(jiān)理合同
- 2025年度電子設(shè)備搬運(yùn)與數(shù)據(jù)安全保護(hù)合同2篇
- 野生植物保護(hù)與生態(tài)交通規(guī)劃考核試卷
- 植物種植培訓(xùn)課程設(shè)計(jì)
- 2025年度戶外廣告牌安全檢測(cè)與維修服務(wù)合同3篇
- 2025版食品加工廠特色食材采購(gòu)合作框架協(xié)議3篇
- 酒店餐飲服務(wù)中的營(yíng)養(yǎng)與健康理念考核試卷
- 2025版低碳環(huán)保鋼筋產(chǎn)品買賣及認(rèn)證服務(wù)合同3篇
- 組態(tài)王課程設(shè)計(jì)工控
- 2024國(guó)際海外銷售代理合同范本
- 上海市市轄區(qū)(2024年-2025年小學(xué)四年級(jí)語(yǔ)文)人教版期末考試(上學(xué)期)試卷及答案
- 期末檢測(cè)卷(試題)-2024-2025學(xué)年三年級(jí)上冊(cè)統(tǒng)編版語(yǔ)文
- 膝關(guān)節(jié)骨性關(guān)節(jié)炎階梯治療
- 2024-2030年中國(guó)工業(yè)真空系統(tǒng)行業(yè)市場(chǎng)發(fā)展趨勢(shì)與前景展望戰(zhàn)略分析報(bào)告
- 新疆第十三師新星經(jīng)濟(jì)技術(shù)開發(fā)區(qū)管委會(huì)招聘筆試題庫(kù)2024
- 2024-2030年中國(guó)毫米波行業(yè)市場(chǎng)發(fā)展趨勢(shì)與前景展望戰(zhàn)略分析報(bào)告
- 2024年全國(guó)初中數(shù)學(xué)競(jìng)賽試題含答案
- 軟裝公司運(yùn)營(yíng)計(jì)劃書
- 中醫(yī)臨床基礎(chǔ)研究設(shè)計(jì)方法與進(jìn)展智慧樹知到期末考試答案2024年
- 手術(shù)室急救設(shè)備
評(píng)論
0/150
提交評(píng)論