We will first make necessary modifications to the API project, and then switch to the Web project to update the client.
Step 1: We need a database.
We need to create a database before doing anything. In this example, SQL Server Express will be used. If it is not installed, you can download SQL Server Express from here. After the installation is completed, create a database named CallingWebApiFromMvc. This is the first step.
The Api project also needs a database connection string, otherwise we can't move forward. Insert the following code into the Web.config file of the Api project:
& ltconnectionStrings & gt
& ltadd name = " ApiFromMvcConnection " connectionString = " Data Source =(local); Initial directory = CallingWebapiFrommVCIntegrated Security = true "Providername =" system. Data.SqlClient" />& lt/connection strings & gt;
Identity framework will automatically create the membership tables we need to manage users, so there is no need to worry about creating them in advance now.
Step 2: Add related Nuget packages.
Next, we add the Nuget package for OWIN and Windows authentication. Open the package management console, switch the Api project to the default project, and enter the following command:
Install Microsoft. AspNet.WebApi.Owin
Install Microsoft. Owin.Host.SystemWeb
Install Microsoft. AspNet . identity . entity framework
Install Microsoft. AspNet.Identity.Owin
Using these packages, we can start an OWIN server in the application and then save our users to SQL Server through EntityFramework.
Step 3: Add the identity class of the administrative user.
We use an entity framework based on Windows authentication mechanism to manage database-related business. First, we need to add some classes for processing. Add an identity directory to the Api project as the namespace of the class we want to add. Then add the following classes:
Public class application users: identify users
{
}
Public class applicationdbcontext: identitydbcontext <; Application users & gt
{ public ApplicationDbContext():base(" apifromvcconnection "){ }
Public static application DbContext Create ()
{ return new ApplicationDbContext();
}
}
Note that the parameter ApiFromMvcConnection that we pass to the base class constructor should match the name in the connection string in Web.config.
Public class Application User Manager: User Manager <: Application users & gt
{public application user manager (IUserStore & lt application user & gt store): base (store)
{
} public static application user manager create (identityfactoryoptions <: ApplicationUserManager & gt option, low context)
{ var manager = new application user manager(new user store & lt; Application user > (context. Get & ltApplicationDbContext & gt ());
//Configure authentication logic for user name.
Manager. user validator = new user validator & lt; Application User & gt (Manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
//Configure the verification logic of the password
Manager. PasswordValidator = new passwordvalidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
Require capital = true,
}; var data protection provider = options。 DataProtectionProvider
if (dataProtectionProvider! = empty)
{
Manager. UserTokenProvider = new data protectortokenprovider & lt; Application user > (data protection provider. Create("ASP。 Screen name "));
} return manager;
}
}
Step 4: Add OWIN startup class
In order for our application to run as an OWIN server, we need to initialize it when the application starts. We can do this through a startup class. We will decorate this kind
OwinStartup property, so it is triggered when the application starts. This also means that we can get rid of Global.asax and move them away.
The Application_Start code is converted into our new startup class.
Use Microsoft. Owin
[assembly:OwinStartup(type of(Levelnis。 learning . callingwebapifrommvc . API . startup))]
Namespace level. learning . calling webapifrommvc . API
{
Use the system;
Use the system. Web . Http
Use identity;
Use Microsoft. Owin . Security.OAuth
Use Owin
Use provider;
Public class startup
{public void configuration (IAppBuilder application)
{
Global configuration. Configuration (WebApiConfig. Registration);
app。 CreatePerOwinContext(ApplicationDbContext。 Create);
app。 CreatePerOwinContext & ltApplicationUserManager & gt(ApplicationUserManager。 Create); var oauth options = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new path string ("/api/token"),
provider = new ApplicationOAuthProvider(),
AccessTokenExpireTimeSpan = TimeSpan。 FromDays( 1),
AllowInsecureHttp = true
};
//Allow applications to authenticate users with anonymous tokens.
app。 UseOAuthBearerTokens(oauth options);
}
}
}
When the application started, we were building our own server. Here, we configure token endpoints and set up our own custom providers, and we use our users for authentication. In our example, we used the ApplicationOAuthProvider class. Let's see now:
Step 5: Add a provider for OAuth
Public class applicationoauthprovider: oauthorizationserverprovider
{public coverage task validateclientauthentication (oauthvaldateclientauthentication context)
{
Context. Verified ();
Return to the task. FromResult & ltobject & gt (empty);
}
Public rewriting asynchronous task grantresourceownercoredidentials (OAuthgrantresourceownercoredidentialsContext)
{
Var userManager = context. OwinContext . GetUserManager & ltApplicationUserManager & gt();
var user = await userManager。 FindAsync (context user name, context. Password);
if (user == null)
{
Context. SetError("invalid_grant ","User name or password is incorrect. " ); Return;
}
Var oAuthIdentity = await user. GenerateUserIdentityAsync(user manager,OAuthDefaults。 AuthenticationType); Var cookiesIdentity = await user. GenerateUserIdentityAsync(user manager,CookieAuthenticationDefaults。 AuthenticationType); var properties = create properties(user。 User name); var ticket = new AuthenticationTicket(oauth identity,properties);
Context. Verified (ticket);
Context. request . context . authentic ation . sign in(cookies identity);
}
Private Static Authentication Attribute Create Attribute (String User Name)
{
Var data = new dictionary & ltstring, string & gt
{
{
"user name", user name
}
};
Returns the new AuthenticationProperties (data);
}
}
We are interested in two methods here. First of all, ValidateClientAuthentication only verifies the client. We have a client, so we return.
Work. This is an asynchronous method signature, but no asynchronous call occurred. Because of this, we can leave asynchronous modification, but we must return to a task ourselves. We added a name.
GenerateUserIdentityAsync's ApplicationUser looks like this method:
Public class application users: identify users
{public asynchronous task & ltclaimsidity & gtgenerateseridentityasync (user manager <: Application user & gt manager, string authentication type)
{
var userIdentity = await manager。 CreateIdentityAsync(this,authenticationType);
Returns the user ID;
}
}
Step 6: Register a new user API.
Therefore, we already have all the identity class management users. Let's take a look at the RegisterController and save the new user in our database. It accepts a simple RegisterApi pattern:
Public class RegisterApiModel
{
[required]
[EmailAddress] public string Email {get setting; }
[required]
[StringLength( 100, ErrorMessage = "The length of this {0} must be at least {2} characters." , minimum length = 6)]
Public string password {
Get settings;
}
[required]
[Display (Name = "Confirm password")]
[Compare("Password ",ErrorMessage =" Password and confirmation password do not match. " )]
Common string ConfirmPassword {get setting; }
}
If the registration is successful, the controller itself only returns a 200 OK response. If the verification fails, the response of 40 1 error request is returned.
Public class registercontroller: apicontroller
{Private Application User Manager User Manager
{get
{Return request. GetOwinContext()。 GetUserManager & ltApplicationUserManager & gt();
}
} public ihttpactionresult post (registerapi model model)
{If (! Model state. IsValid)
{ return bad request(model state);
} var user = new application user
{
Mail = model. E-mail,
User name = model. E-mail,
EmailConfirmed = true
};
var result = UserManager。 Create (user, model. Password);
Return the results. Did it work? Ok(): GetErrorResult (result);
}
Private ihttpactionresult get error result (identity result)
{
If (result == null)
{
Returns internal server error ();
}
If (as a result. Wrong! = empty)
{
Foreach (Error in variable in result. Error)
{
Model state. AddModelError (",error);
}
}
if (ModelState。 IsValid)
{
//There is no ModelState error to send, so only an empty BadRequest is returned.
Return badrequest ();
}
Return bad request (model state);
}
}