首先到http://open.weibo.com/development 注册一个开发者账号。
然后可以点微连接--网站接入
会分配App Key 和App Secret
然后点高级信息
在这里设置回调地址
这里的回调地址不能用localhost,后面再说怎么来设置这个
新建web项目
为了方便调试,在项目属性的Web中选择本地IIS
保存会提示创建虚拟目录
注意:如果是用本地IIS的话,需要把数据库连接改下,不能用程序自带的LocalDB
运行即可看到页面
此时需要请出一款神器:ngrok
下载后解压,命令行到解压目录,运行
ngrok -config=ngrok.cfg -subdomain mywebapp 80
在浏览器访问:http://mywebapp.tunnel.qydev.com/MyWebApp/
好了,这个时候再来设置回调地址:
修改Views--Account 下的_ExternalLoginsListPartial.cshtml
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
@model MyWebApp.Models.ExternalLoginListViewModel @using Microsoft.Owin.Security <h4>使用其他服务登录。</h4> <hr /> @{ using (Html.BeginForm("ExternalLogin", "Account", new { ReturnUrl = Model.ReturnUrl })) { @Html.AntiForgeryToken() <div id="socialLoginList"> <p> <button type="submit" class="btn btn-default" id="" name="provider" value="" title="使用你的 微博 帐户登录">微博登录</button> </p> </div> } }
修改AccountController--ExternalLogin
public ActionResult ExternalLogin(string provider, string returnUrl) { // 请求重定向到外部登录提供程序 string url = "https://api.weibo.com/oauth2/authorize?client_id=xxx&response_type=code&redirect_uri=http://mywebapp.tunnel.qydev.com/MyWebApp/Account/ExternalLoginCallback"; return Redirect(url); //return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl })); }
这里的client_id就是上面微博分配的App Key
修改ExternalLoginCallback
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public async Task<ActionResult> ExternalLoginCallback(string returnUrl) { string appKey = "app key"; string appSecret = "app secret"; string code = Request["code"]; string url = string.Format("https://api.weibo.com/oauth2/access_token"); string callBack = "http://mvctest.tunnel.qydev.com/MvcWebApp/Account/ExternalLoginCallback"; NameValueCollection collection = new NameValueCollection(); collection.Add("client_id", appKey); collection.Add("client_secret", appSecret); collection.Add("grant_type", "authorization_code"); collection.Add("code", code); collection.Add("redirect_uri", callBack); try { using (WebClient client = new WebClient()) { client.Encoding = Encoding.UTF8; byte[] response = client.UploadValues(url, collection); var returnStr = Encoding.UTF8.GetString(response); OAuthEntity oauth = JsonConvert.DeserializeObject<OAuthEntity>(returnStr); //获取用户信息 string userUrl = string.Format("https://api.weibo.com/2/users/show.json?access_token={0}&uid={1}", oauth.access_token, oauth.uid); var userInfo = client.DownloadString(userUrl); SinaUser sinaUser = JsonConvert.DeserializeObject<SinaUser>(userInfo); UserLoginInfo login = new UserLoginInfo("sina", sinaUser.name); var appUser = await UserManager.FindAsync(login); if (appUser != null) { await SignInManager.SignInAsync(appUser, isPersistent: false, rememberBrowser: false); if (string.IsNullOrEmpty(returnUrl)) { return RedirectToAction("Index", "Home"); } return RedirectToLocal(returnUrl); } else { ViewBag.ReturnUrl = returnUrl; ViewBag.LoginProvider = "sina"; return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = sinaUser.name + "@myweb.com", UserName = sinaUser.screen_name }); } } } catch (Exception ex) { return RedirectToAction("Login"); } }
需要注意的是请求token必须是用Post,而且callBack必须和回调地址一致。
因为新浪微博用户信息没有返回邮箱,所以这里随便加了个@myweb.com
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = sinaUser.name + "@myweb.com", UserName = sinaUser.screen_name });
否则后面注册的时候验证Email不通过。
这里添加了两个类,用来接收token和用户信息,直接放到AccountViewModels里面。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public class OAuthEntity { public string access_token { get; set; } public string remind_in { get; set; } public long expires_in { get; set; } public string uid { get; set; } } public class SinaUser { /// <summary> /// 用户UID /// </summary> public long id { get; set; } /// <summary> /// 用户昵称 /// </summary> public string screen_name { get; set; } /// <summary> /// 友好显示名称 /// </summary> public string name { get; set; } /// <summary> /// 性别,m:男、f:女、n:未知 /// </summary> public string gender { get; set; } /// <summary> /// 用户创建(注册)时间 /// </summary> public string created_at { get; set; } /// <summary> /// 用户头像地址(中图),50×50像素 /// </summary> public string profile_image_url { get; set; } /// <summary> /// 用户头像地址(大图),180×180像素 /// </summary> public string avatar_large { get; set; } /// <summary> /// 用户头像地址(高清),高清头像原图 /// </summary> public string avatar_hd { get; set; } }
修改添加一个用户名
public class ExternalLoginConfirmationViewModel { [Display(Name = "电子邮件")] public string Email { get; set; } /// <summary> /// 用户名 /// </summary> [Display(Name = "用户名")] public string UserName { get; set; } }
修改ExternalLoginConfirmation
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl) { if (User.Identity.IsAuthenticated) { return RedirectToAction("Index", "Manage"); } if (ModelState.IsValid) { // 从外部登录提供程序获取有关用户的信息 UserLoginInfo info = new UserLoginInfo("sina", model.UserName); var user = new ApplicationUser { UserName = model.Email, Email = model.Email }; var result = await UserManager.CreateAsync(user); if (result.Succeeded) { result = await UserManager.AddLoginAsync(user.Id, info); if (result.Succeeded) { await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); return RedirectToLocal(returnUrl); } } AddErrors(result); } ViewBag.ReturnUrl = returnUrl; return View(model); }
修改下ExternalLoginConfirmation.cshtml页面
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
@model MyWebApp.Models.ExternalLoginConfirmationViewModel @{ ViewBag.Title = "注册"; } <h2>@ViewBag.Title。</h2> <h3>关联你的 @ViewBag.LoginProvider 帐户。</h3> @using (Html.BeginForm("ExternalLoginConfirmation", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) { @Html.AntiForgeryToken() <h4>关联表单</h4> <hr /> @Html.ValidationSummary(true, "", new { @class = "text-danger" }) <p class="text-info"> 你已成功使用 <strong>@ViewBag.LoginProvider</strong> 进行身份验证。 请在下面输入此站点的用户名,然后单击“注册”按钮完成 登录。 </p> <div class="form-group"> @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) @Html.ValidationMessageFor(m => m.Email, "", new { @class = "text-danger" }) </div> @Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.TextBoxFor(m => m.UserName, new { @class = "form-control" }) @Html.ValidationMessageFor(m => m.UserName, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" class="btn btn-default" value="注册" /> </div> </div> } @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
准备完毕了,运行,点击登录
这里就有微博登录了,先不着急用微博登录,先注册新用户,让程序把库建好
成功后会自动登录
看看ASP.Net Identity 通过 EF CodeFirst建的表
接下来试试微博登录,先注销当前账户,再点击登录,这次点击微博登录
会跳转到微博认证
登录后会跳转回来并带有code
http://mywebapp.tunnel.qydev.com/MyWebApp/Account/ExternalLoginCallback?code=dde370ced7025b82572fbe9b29ae5a6d
在后台通过调用token接口获取token后再获取用户信息
如果用户没有注册过,跳转到注册页面
注册后自动登录
此时可以看看表里的变化
AspNetUsers表:
[AspNetUserLogins]表:
再次登录就不用注册了。
Identity的表也可以方便扩展,比如给AspNetUsers添加一个[DisplayName]字段
首先开启EF Codefirst 的自动迁移
Enable-Migrations –EnableAutomaticMigrations
会生成一个目录和一个Configuration文件
然后执行
Add-Migration Init
再执行
Update-Database
也可以加上-v 查看具体的sql
之后在ApplicationUser类里面添加DisplayName
在注册的控制器里添加
更新注册页面
更新RegisterViewModel类
再次运行
update-database -v
之后重新注册
注册成功后看数据库