Use OAuth and Identity to create a WebApi authentication interface for the client to call.
Preface
Currently, web apps are basically isolated from the frontend and backend. Most of the application scenarios that were previously used, the final products are deployed under the same site) the front-end is not developed on the page of the backend framework, and the traditional Session is used to determine the Client Login User. OAuth has been released for a long time, and Asp. Net Identity has been released for a long time. After reading a few blogs written by friends, I wrote these samples and solved some of my doubts about the complete separation of the front and back ends.
Four OAuth2.0 roles
- Resource owner: for example, a twitter user, whose data on twitter is a resource, and the resource owner is the resource owner.
- Resource server: the server that saves the resource. If someone else wants to Access the restricted resource, the Access Token (Access another card) will be presented)
- Client: A Party authorized to access restricted resources on the resource server on behalf of the resource owner. For example, applications developed by developers
- Authorization server: authenticates the resource owner. After the authentication is passed, the Access Token (Access another card) is issued to the client.
OAuth2.0 provides four Access Token Methods
- Authorization code)
- Implicit)
- Resource owner password credentials)
- Client credentials)
Use Owin to implement password mode (OAuth2.0 password Mode)
1. Use VS2015 to create an Empty WebApi project.
2. Use Nuget to import the core namespace.
Install-Package Microsoft. AspNet. WebApi. Owin
Install-Package Microsoft. Owin. Host. SystemWeb
3. added the OwinStartup attribute to the Startup class of the Owin entry class, which indicates that this class serves as the entry of the Owin class.
[assembly:OwinStartup(typeof(AspNet_Identity_Demo.Startup))]namespace AspNet_Identity_Demo{ public class Startup { public void Configuration(IAppBuilder app) { HttpConfiguration config = new HttpConfiguration(); WebApiConfig.Register(config); app.UseWebApi(config); } }}
4. Modify WebApiConfig. Modify the last two sentences of code, mainly using the CamelCase naming method to serialize the returned results of webApi.
Namespace AspNet_Identity_Demo {public static class WebApiConfig {public static void Register (HttpConfiguration config) {// Web API configuration and service // Web API route config. mapHttpAttributeRoutes (); config. routes. mapHttpRoute (name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new {id = RouteParameter. optional}); // return the webapi return value var jsonFormatter = config in json format. formatters. ofType <JsonMediaTypeFormatter> (). first (); jsonFormatter. serializerSettings. contractResolver = new CamelCasePropertyNamesContractResolver ();}}}
5. Delete Global. asax. This class is temporarily unavailable after the Startup class is added.
6. Add Asp. Net Identity. Add the Identity Class Library first.
Install-Package Microsoft. AspNet. Identity. Owin
Install-Package Microsoft. AspNet. Identity. EntityFramework
The first package provides support for Asp. Net Identity Owin, and the second package provides Owin implementation based on ef SQL Server. Microsoft. aspNet. identity. core Package, which is mainly related to the implementation of Asp.net Identity, for example, IUser, IRole, IPasswordHasher, IUserStore <TUser>, IUseRoleStore <TUser>, IRoleStore <TUser>, IClamisIdentityFactory <TUser>, UserManager <TUser>, and IdentiyResult. In the second package, we will first see IdentityDbContext <TUser>, IdentityUser, IdentityRole, and UserStore. You want to create user class inheritance IUser or IdentityUser based on your user system extension. If you want to change to another database, you can customize DbContext. 7. Create an AuthContext.
namespace AspNet_Identity_Demo.Models{ public class AuthContext:IdentityDbContext<IdentityUser> { public AuthContext() : base("AuthContext") { } }}
Add connectionString in Web. config
<add name="AuthContext" connectionString="Data Source=.;User Id=sa;password=111111;Initial Catalog=AspNet_Identity;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
8. Create UserModel. cs in the Models folder.
public class UserModel { [Required] [Display(Name ="User Name")] public string UserName { get; set; } [Required] [DataType(DataType.Password)] [StringLength(100,ErrorMessage ="The {0} must be at least {2} characters long",MinimumLength =6)] public string Password { get; set; } [Required] [DataType(DataType.Password)] [Compare("Password",ErrorMessage ="The password and confirmpassword are not matched...")] public string ConfirmPassword { get; set; } }
9. added the Asp. Net Identity warehousing support class.
The policy mode is used to pass your implemented UserStore. cs as parameters to the UserManager constructor.
namespace AspNet_Identity_Demo.Models{ public class AuthRepository : IDisposable { private AuthContext _ctx; private UserManager<IdentityUser> _userManager; public AuthRepository() { _ctx = new AuthContext(); _userManager = new UserManager<IdentityUser>(new UserStore<IdentityUser>(_ctx)); } public async Task<IdentityResult> Register(UserModel model) { IdentityUser user = new IdentityUser() { UserName = model.UserName }; IdentityResult result = await _userManager.CreateAsync(user,model.Password); return result; } public async Task<IdentityUser> FindUser(UserModel model) { IdentityUser user = await _userManager.FindAsync(model.UserName, model.Password); return user; } public async Task<IdentityUser> FindUserByName(string username) { IdentityUser user = await _userManager.FindByNameAsync(username); return user; } public void Dispose() { _ctx.Dispose(); _userManager.Dispose(); } }}
10. Add AccountController. cs
Add a webapi access prefix to the Controller. My website is apix, Which is http: // localhost: 8083/apix/account/register.
namespace AspNet_Identity_Demo.Controllers{ [RoutePrefix("apix/Account")] public class AccountController : ApiController { private AuthRepository _authRepo; public AccountController() { _authRepo = new AuthRepository(); } [AllowAnonymous] [Route("Register")] public async Task<IHttpActionResult> Register(UserModel model) { if (!ModelState.IsValid) { return BadRequest(ModelState); } IdentityResult result = await _authRepo.Register(model); IHttpActionResult errorResult = GetError(result); if (errorResult != null) { return errorResult; } return Ok(); } private IHttpActionResult GetError(IdentityResult result) { if (result == null) { return InternalServerError(); } if (!result.Succeeded) { foreach (string err in result.Errors) { ModelState.AddModelError("", err); } if (ModelState.IsValid) { return BadRequest(); } return BadRequest(ModelState); } return null; } }}
OK. Now you can register a user above your sight. Use Postman to call the interface and call the interface http: // localhost: 8080/apix/account/register. Post method call. Specify UserName and Password. If the call is successful, interface 200 is returned. Open your SQL Server. If the call is successful, several tables used by the database are generated. The User table is dbo. AspNetUsers.
11. Add a data access controller, OrdersController.
namespace AspNet_Identity_Demo.Controllers{ [Authorize] [RoutePrefix("apix/orders")] public class OrdersController : ApiController { [Route] public IHttpActionResult Get() { return Ok(Order.CreateOrders()); } } public class Order { public int OrderID { get; set; } public string CustomerName { get; set; } public string ShipperCity { get; set; } public Boolean IsShipped { get; set; } public static List<Order> CreateOrders() { List<Order> OrderList = new List<Order> { new Order {OrderID = 10248, CustomerName = "Taiseer Joudeh", ShipperCity = "Amman", IsShipped = true }, new Order {OrderID = 10249, CustomerName = "Ahmad Hasan", ShipperCity = "Dubai", IsShipped = false}, new Order {OrderID = 10250,CustomerName = "Tamer Yaser", ShipperCity = "Jeddah", IsShipped = false }, new Order {OrderID = 10251,CustomerName = "Lina Majed", ShipperCity = "Abu Dhabi", IsShipped = false}, new Order {OrderID = 10252,CustomerName = "Yasmeen Rami", ShipperCity = "Kuwait", IsShipped = true} }; return OrderList; } }}
12. added the OAuth Bearer Token Support class library Install-Package Microsoft. Owin. Security. OAuth
13. Return to Startup. The ADD and create token method involves SimpleAuthorizationServerProvider and OAuthAuthorizationServerOptions.
[assembly:OwinStartup(typeof(AspNet_Identity_Demo.Startup))]namespace AspNet_Identity_Demo{ public class Startup { public void Configuration(IAppBuilder app) { HttpConfiguration config = new HttpConfiguration(); ConfigAuth(app); WebApiConfig.Register(config); app.UseCors(CorsOptions.AllowAll); app.UseWebApi(config); } public void ConfigAuth(IAppBuilder app) { OAuthAuthorizationServerOptions option = new OAuthAuthorizationServerOptions() { AllowInsecureHttp=true, TokenEndpointPath=new PathString("/token"), AccessTokenExpireTimeSpan=TimeSpan.FromDays(1), Provider=new SimpleAuthorizationServerProvider() }; app.UseOAuthAuthorizationServer(option); app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); } } public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider { public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { context.Validated(); } public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); using (AuthRepository _repo = new AuthRepository()) { IdentityUser user =await _repo.FindUser( new UserModel() { UserName=context.UserName,Password=context.Password}); if (user == null) { context.SetError("invalid_grant", "The username or password is incorrect"); return; } } var identity = new ClaimsIdentity(context.Options.AuthenticationType); identity.AddClaim(new Claim("sub", context.UserName)); identity.AddClaim(new Claim("role", "user")); context.Validated(identity); } }}
Access http: // localhost: 8083/token http interface to generate a token. The expiration time is 24 hours. SimpleAuthorizationServerProvider Implements user authentication and password generation in this class. Note the ClamisIdentity here. This class is in the namespace: System. Security. Claims. The token is generated mainly by context. Validated (identity.
OK. Now you can register a user or generate a token. Now there is a problem. After the front and back ends are completely separated, you must implement cross-origin access (CORS ). Therefore, you can see that the first sentence of rewriting GrantResourceOwnerCredentials is to add Access-Control-Allow-Origin support.
13. Add Asp. Net WebApi Install-Package Microsoft. Owin. Cors. Add app. UseCors (CorsOptions. AllowAll) in the Startup. cs Configuration method );
14. Generate the client token.
15. Access the data interface after obtaining the token. Note that the Authorization value of the parameter is prefixed with Bearer.
Summary
In general, the design of Owin and Identity is a bit complicated, with more conventions. Compared with the Membership that Microsoft got up early, it is much more elegant, and the details behind the principles and implementations need to be explored in order to realize the charm. For example, ClamisIdentity, UserManager, and UserStore.
References
Http://www.cnblogs.com/richieyang/p/4918819.html
Http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/
Http://www.haomou.net/2014/08/13/2014_bare_token/
Http://www.cnblogs.com/pengyingh/articles/2377968.html
Http://www.cnblogs.com/keepfool/p/5665953.html