具有 ASP.NET 身份的 Azure 移动应用程序
Azure Mobile App with ASP.NET Identity
我的情况是:我已经实现了具有身份和 Register/Login 操作的 ASP.NET WebAPI 应用程序。这是我的 ApiAccountController:
[Authorize]
[RoutePrefix("api/Account")]
public class ApiAccountController : ApiController
{
private const string LocalLoginProvider = "Local";
private ApplicationUserManager _userManager;
public ApiAccountController()
{
}
public ApiAccountController(ApplicationUserManager userManager,
ISecureDataFormat<AuthenticationTicket> accessTokenFormat)
{
UserManager = userManager;
AccessTokenFormat = accessTokenFormat;
}
public ApplicationUserManager UserManager
{
get { return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>(); }
private set { _userManager = value; }
}
public ISecureDataFormat<AuthenticationTicket> AccessTokenFormat { get; }
// POST api/Account/Register
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterViewModel model)
{
if (!ModelState.IsValid) return BadRequest(ModelState);
var user = new ApplicationUser
{
Name = model.Nome,
UserName = model.Email,
Email = model.Email,
CidadeId = model.CidadeId
};
var result = await UserManager.CreateAsync(user, model.Password);
//return !result.Succeeded ? GetErrorResult(result) : Ok();
if (result.Succeeded)
{
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = new Uri(Url.Link("ConfirmEmailRoute", new { userId = user.Id, code }));
await
UserManager.SendEmailAsync(user.Id, "Confirme Sua Conta",
"Para confirmar sua conta, clique <a href=\"" + callbackUrl + "\">Aqui!</a>");
// Uri locationHeader = new Uri(Url.Link("GetUserById", new { id = user.Id }));
return Ok();
}
return GetErrorResult(result);
}
[HttpGet]
[AllowAnonymous]
[Route("ConfirmEmail", Name = "ConfirmEmailRoute")]
public async Task<IHttpActionResult> ConfirmEmail(Guid userId, string code)
{
if (string.IsNullOrEmpty(userId.ToString()) || string.IsNullOrWhiteSpace(code))
{
ModelState.AddModelError("", "Códigos necessários");
return BadRequest(ModelState);
}
var result = await UserManager.ConfirmEmailAsync(userId, code);
if (result.Succeeded)
return Ok("Conta confirmada! Obrigado pela preferência, agora você pode utilizar nosso novo app");
return GetErrorResult(result);
}
[HttpPost]
[AllowAnonymous]
[Route("Login")]
public async Task<IHttpActionResult> Login(LoginUserViewModel model)
{
var request = HttpContext.Current.Request;
var tokenServiceUrl = request.Url.GetLeftPart(UriPartial.Authority) + request.ApplicationPath + "/Token";
using (var client = new HttpClient())
{
var requestParams = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("username", model.Username),
new KeyValuePair<string, string>("password", model.Password)
};
var requestParamsFormUrlEncoded = new FormUrlEncodedContent(requestParams);
var tokenServiceResponse = await client.PostAsync(tokenServiceUrl, requestParamsFormUrlEncoded);
var responseString = await tokenServiceResponse.Content.ReadAsStringAsync();
if (tokenServiceResponse.StatusCode != HttpStatusCode.OK) return BadRequest();
using (var tx = new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted },
TransactionScopeAsyncFlowOption.Enabled))
{
try
{
var user = UserManager.FindByName(model.Username);
if (user == null) return NotFound();
if (!user.EmailConfirmed) return BadRequest();
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(responseString);
user.AccessToken = json["access_token"];
UserManager.Update(user);
tx.Complete();
var vm = user.Adapt<UserLoggedViewModel>();
return Ok(vm);
}
catch
{
tx.Dispose();
throw;
}
}
}
}
// POST api/Account/Logout
[Route("Logout")]
public IHttpActionResult Logout()
{
Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
return Ok();
}
// Some actions was removed
#region Helpers
private IAuthenticationManager Authentication
{
get { return Request.GetOwinContext().Authentication; }
}
private IHttpActionResult GetErrorResult(IdentityResult result)
{
if (result == null)
return InternalServerError();
if (!result.Succeeded)
{
if (result.Errors != null)
foreach (var error in result.Errors)
ModelState.AddModelError("", error);
if (ModelState.IsValid)
return BadRequest();
return BadRequest(ModelState);
}
return null;
}
#endregion
}
这是我的Start.Auth配置
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity =
SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser, Guid>(
TimeSpan.FromMinutes(30),
(manager, user) =>
user.GenerateUserIdentityAsync(manager, DefaultAuthenticationTypes.ApplicationCookie),
id => Guid.Parse(id.GetUserId()))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
// Enables the application to remember the second login verification factor such as phone or email.
// Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
// This is similar to the RememberMe option when you log in.
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(7),
RefreshTokenProvider = new RefreshTokenProvider(),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
//var options = new AppServiceAuthenticationOptions()
//{
// SigningKey = ConfigurationManager.AppSettings["SigningKey"],
// ValidAudiences = new[] {ConfigurationManager.AppSettings["ValidAudience"]},
// ValidIssuers = new[] {ConfigurationManager.AppSettings["ValidIssuer"]},
// TokenHandler = WebApiConfig.Configuration.GetAppServiceTokenHandler()
//};
//app.UseAppServiceAuthentication(options);
}
}
WebAPIConfig
public static class WebApiConfig
{
//public static HttpConfiguration Configuration { get; private set; }
public static void Register(HttpConfiguration config)
{
//Configuration = config;
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
"DefaultApi",
"api/{controller}/{id}",
new {id = RouteParameter.Optional}
);
var container = LightInjectContainer.Register();
container.RegisterApiControllers();
container.EnableWebApi(config);
MapsterConfig.RegisterMappings();
// Database.SetInitializer<SolumDbContext>(null);
// new MobileAppConfiguration()
// .UseDefaultConfiguration()
// .ApplyTo(config);
}
}
这是完全可用的,我将它与我的移动应用程序一起使用。但是,我想将 azure 离线同步与每用户数据同步结合使用。阅读 Google 上的一些文章,没有人确切说明如何在移动应用程序上使用身份。所有文章都说要阅读有关如何配置自定义登录提供程序的 Microsoft 文档,但它们都没有解释如何准确配置。我已经在这里阅读了一些帖子。有些人和我有同样的问题,但没有人有解决方案,一个如何使用这个的真实例子,或者我没有找到这个。
明确地说,我想将我的身份配置与 Azure 移动应用程序一起使用,并使用 azure 离线同步功能同步每个用户的数据。
有人可以帮我解决这个问题吗?
真的很感谢!
你需要阅读我的书的第 2 章 - http://aka.ms/zumobook
我的情况是:我已经实现了具有身份和 Register/Login 操作的 ASP.NET WebAPI 应用程序。这是我的 ApiAccountController:
[Authorize]
[RoutePrefix("api/Account")]
public class ApiAccountController : ApiController
{
private const string LocalLoginProvider = "Local";
private ApplicationUserManager _userManager;
public ApiAccountController()
{
}
public ApiAccountController(ApplicationUserManager userManager,
ISecureDataFormat<AuthenticationTicket> accessTokenFormat)
{
UserManager = userManager;
AccessTokenFormat = accessTokenFormat;
}
public ApplicationUserManager UserManager
{
get { return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>(); }
private set { _userManager = value; }
}
public ISecureDataFormat<AuthenticationTicket> AccessTokenFormat { get; }
// POST api/Account/Register
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterViewModel model)
{
if (!ModelState.IsValid) return BadRequest(ModelState);
var user = new ApplicationUser
{
Name = model.Nome,
UserName = model.Email,
Email = model.Email,
CidadeId = model.CidadeId
};
var result = await UserManager.CreateAsync(user, model.Password);
//return !result.Succeeded ? GetErrorResult(result) : Ok();
if (result.Succeeded)
{
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = new Uri(Url.Link("ConfirmEmailRoute", new { userId = user.Id, code }));
await
UserManager.SendEmailAsync(user.Id, "Confirme Sua Conta",
"Para confirmar sua conta, clique <a href=\"" + callbackUrl + "\">Aqui!</a>");
// Uri locationHeader = new Uri(Url.Link("GetUserById", new { id = user.Id }));
return Ok();
}
return GetErrorResult(result);
}
[HttpGet]
[AllowAnonymous]
[Route("ConfirmEmail", Name = "ConfirmEmailRoute")]
public async Task<IHttpActionResult> ConfirmEmail(Guid userId, string code)
{
if (string.IsNullOrEmpty(userId.ToString()) || string.IsNullOrWhiteSpace(code))
{
ModelState.AddModelError("", "Códigos necessários");
return BadRequest(ModelState);
}
var result = await UserManager.ConfirmEmailAsync(userId, code);
if (result.Succeeded)
return Ok("Conta confirmada! Obrigado pela preferência, agora você pode utilizar nosso novo app");
return GetErrorResult(result);
}
[HttpPost]
[AllowAnonymous]
[Route("Login")]
public async Task<IHttpActionResult> Login(LoginUserViewModel model)
{
var request = HttpContext.Current.Request;
var tokenServiceUrl = request.Url.GetLeftPart(UriPartial.Authority) + request.ApplicationPath + "/Token";
using (var client = new HttpClient())
{
var requestParams = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("username", model.Username),
new KeyValuePair<string, string>("password", model.Password)
};
var requestParamsFormUrlEncoded = new FormUrlEncodedContent(requestParams);
var tokenServiceResponse = await client.PostAsync(tokenServiceUrl, requestParamsFormUrlEncoded);
var responseString = await tokenServiceResponse.Content.ReadAsStringAsync();
if (tokenServiceResponse.StatusCode != HttpStatusCode.OK) return BadRequest();
using (var tx = new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted },
TransactionScopeAsyncFlowOption.Enabled))
{
try
{
var user = UserManager.FindByName(model.Username);
if (user == null) return NotFound();
if (!user.EmailConfirmed) return BadRequest();
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(responseString);
user.AccessToken = json["access_token"];
UserManager.Update(user);
tx.Complete();
var vm = user.Adapt<UserLoggedViewModel>();
return Ok(vm);
}
catch
{
tx.Dispose();
throw;
}
}
}
}
// POST api/Account/Logout
[Route("Logout")]
public IHttpActionResult Logout()
{
Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
return Ok();
}
// Some actions was removed
#region Helpers
private IAuthenticationManager Authentication
{
get { return Request.GetOwinContext().Authentication; }
}
private IHttpActionResult GetErrorResult(IdentityResult result)
{
if (result == null)
return InternalServerError();
if (!result.Succeeded)
{
if (result.Errors != null)
foreach (var error in result.Errors)
ModelState.AddModelError("", error);
if (ModelState.IsValid)
return BadRequest();
return BadRequest(ModelState);
}
return null;
}
#endregion
}
这是我的Start.Auth配置
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity =
SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser, Guid>(
TimeSpan.FromMinutes(30),
(manager, user) =>
user.GenerateUserIdentityAsync(manager, DefaultAuthenticationTypes.ApplicationCookie),
id => Guid.Parse(id.GetUserId()))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
// Enables the application to remember the second login verification factor such as phone or email.
// Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
// This is similar to the RememberMe option when you log in.
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(7),
RefreshTokenProvider = new RefreshTokenProvider(),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
//var options = new AppServiceAuthenticationOptions()
//{
// SigningKey = ConfigurationManager.AppSettings["SigningKey"],
// ValidAudiences = new[] {ConfigurationManager.AppSettings["ValidAudience"]},
// ValidIssuers = new[] {ConfigurationManager.AppSettings["ValidIssuer"]},
// TokenHandler = WebApiConfig.Configuration.GetAppServiceTokenHandler()
//};
//app.UseAppServiceAuthentication(options);
}
}
WebAPIConfig
public static class WebApiConfig
{
//public static HttpConfiguration Configuration { get; private set; }
public static void Register(HttpConfiguration config)
{
//Configuration = config;
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
"DefaultApi",
"api/{controller}/{id}",
new {id = RouteParameter.Optional}
);
var container = LightInjectContainer.Register();
container.RegisterApiControllers();
container.EnableWebApi(config);
MapsterConfig.RegisterMappings();
// Database.SetInitializer<SolumDbContext>(null);
// new MobileAppConfiguration()
// .UseDefaultConfiguration()
// .ApplyTo(config);
}
}
这是完全可用的,我将它与我的移动应用程序一起使用。但是,我想将 azure 离线同步与每用户数据同步结合使用。阅读 Google 上的一些文章,没有人确切说明如何在移动应用程序上使用身份。所有文章都说要阅读有关如何配置自定义登录提供程序的 Microsoft 文档,但它们都没有解释如何准确配置。我已经在这里阅读了一些帖子。有些人和我有同样的问题,但没有人有解决方案,一个如何使用这个的真实例子,或者我没有找到这个。
明确地说,我想将我的身份配置与 Azure 移动应用程序一起使用,并使用 azure 离线同步功能同步每个用户的数据。
有人可以帮我解决这个问题吗?
真的很感谢!
你需要阅读我的书的第 2 章 - http://aka.ms/zumobook