新增一個 Web Api 專案, 查看 App_Start/Startup.Auth.cs 的這個方法 :
public void ConfigureAuth(IAppBuilder app)
{
// 設定資料庫內容和使用者管理員以針對每個要求使用單一執行個體
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// 讓應用程式使用 Cookie 儲存已登入使用者的資訊
// 並使用 Cookie 暫時儲存使用者利用協力廠商登入提供者登入的相關資訊;
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// 設定 OAuth 基礎流程的應用程式
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// 在生產模式中設定 AllowInsecureHttp = false
AllowInsecureHttp = true
};
// 讓應用程式使用 Bearer 權杖驗證使用者
app.UseOAuthBearerTokens(OAuthOptions);
}
得知 OAuthAuthorizationServerOptions.Provider 使用 ApplicationOAuthProvider, 想要在取 token 所回傳的 json 中加入其他資料(例如 name 和 city), 因此針對他的 GrantResourceOwnerCredentials 方法進行修改 :
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
await Task.Run(() =>
{
// 自行驗證
if (context.UserName == "ian" && context.Password == "1111")
{
// 驗證通過
// 建立一個 ClaimsIdentity
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
// 加入一些自行命名且好讀的 Claim
identity.AddClaim(new Claim("name", "Ian"));
identity.AddClaim(new Claim("city", "Tainan"));
// 建立一個 AuthenticationProperties
var p1 = new Dictionary<string, string>
{
{"name","Ian"}, // 顯示於回傳的json中
{"city","Tainan"}
};
AuthenticationProperties properties = new AuthenticationProperties(p1);
// 使用 ClaimsIdentity 和 AuthenticationProperties 來產生一個 AuthenticationTicket
AuthenticationTicket ticket = new AuthenticationTicket(identity, properties);
// 替換此內容上的票證資訊,並讓其由應用程式驗證。 呼叫之後,IsValidated 為 true 且 HasError 為 false。
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(identity);
}
else
{
context.SetError("invalid_grant", "使用者名稱或密碼不正確。");
return;
}
});
}
測試 :
- POST /token
- form data :
-
-
-
使用 jQuery.ajax 取 Token :
$.ajax({
url: '/token',
data: { username: username, password: password, grant_type: 'password' },
type: 'POST',
success: function (data) {
console.log(data);
$('#token').val(data.access_token);
}
});
結果 :
{
"access_token":"F5PU_EhpbLl7aw_EwlTuP8unNXc4L9olOlqbuan0oQbjPyh-u5iEUjQnRcs7AkV6ia7clMPn8JyZZxNucD5mP_vUTvmeGjDGZJI33qzWzehGP4xQr5HCMQ0EtaCBi7pxq0WttOtLYumoZNXmBDnRWqTtn3s7iBszewS1IHb__J2-zd1nzVmT7VKOVe_GFQhKCB_cXMqCPyfPaERLrzBYjT3ju3RYIrDn1m-ZuaLXwVM","token_type":"bearer","expires_in":1209599,
"name":"Ian",
"city":"Tainan",".issued":"Wed, 02 Sep 2015 07:33:46 GMT",".expires":"Wed, 16 Sep 2015 07:33:46 GMT"}
name 和 city 被加入到回傳的 json 中
在後端程式中使用 ClaimsIdentity 中的資料, 例如取得使用者的 city :
[Authorize]
public class UserCityController : ApiController
{
public string Get()
{
var identity = User.Identity as ClaimsIdentity;
var city = (identity.Claims).Where(x => x.Type == "city").Select(x => x.Value).FirstOrDefault();
return city;
}
}
前端使用 jQuery 撈取 :
$.ajax({
url: '/api/usercity',
type: 'GET',
headers: {
'Authorization': 'Bearer ' + $('#token').val()
},
success: function (data) {
$('#user-city').text(data);
}
});
Authorization : Bearer {token}