"WEB API Project Combat Dry Series"-API Login and authentication (iii)

Source: Internet
Author: User
Tags ssl certificate

Previous: "WEB API Project Combat Dry"-interface documentation and online testing (ii)

This article focuses on how we can complete the API login and identity authentication in the API project. So this chapter will be divided into two parts, login API, API authentication.

The main principle of this article is: The API will provide a separate login API, through the user name, password to generate a SessionKey, SessionKey has the characteristics of expiration time, the system will record this sessionkey, in the subsequent return of each API, The client needs to take this sessionkey, and the API will verify the SessionKey.

Login API

Let's take a look at the method signature of the login API

Sessionobject is the object returned to the client after login, which contains the information of SessionKey and the user currently logged in.

Each time the API calls, all need to pass SessionKey in the past, SessionKey represents the user's identity information, and login expiration information.

SessionKey generated during the login phase we need to save, store into an object called Userdevice, and from the semantics we can know that users who log on through different devices will produce different Userdevice objects.

The final login code is as follows:

[Routeprefix ("api/accounts")] public class Accountcontroller:apicontroller {private ReadOnly Iauthenticati        Onservice _authenticationservice = null; Public AccountController () {//this._authenticationservice = Iocmanager.intance.reslove<iauthenticati        Onservice> (); } [HttpGet] public void Accountsapi () {}///<summary>//Login API/ </summary>//<param name= "Loginidoremail" > Login account (email or other loginID) </param>//<param N Ame= "Hashedpassword" > Password after encryption, here to avoid plaintext, client encrypted after uploading to API side </param>//<param name= "DeviceType" > Client device Type </ param>//<param name= "ClientId" > Client identification number, generally there will be a client identification number on the app </param>//<remarks> Other login bits        What is the client can pass the things, can be expanded here </remarks>///<returns></returns> [Route ("Account/login")] Public Sessionobject Login (string loginidoremail, string Hashedpassword, INT DeviceType = 0, string clientId = "") {if (string. IsNullOrEmpty (Loginidoremail)) throw new Apiexception ("username can ' t be empty.", "Requireparameter_usernam            E "); if (string. IsNullOrEmpty (Hashedpassword)) throw new Apiexception ("Hashedpassword can ' t be empty.", "Requireparameter_h            Ashedpassword ");            int timeout = 60;            var nowuser = _authenticationservice.getuserbyloginid (Loginidoremail);            if (Nowuser = = null) throw new Apiexception ("Account Not Exists", "account_notexits"); #region Verify Password if (!string. Equals (Nowuser.password, Hashedpassword)) {throw new Apiexception ("Wrong Password", "ACCOUNT_WR            Ongpassword "); } #endregion if (!nowuser.isactive) throw new Apiexception ("The user is inactive.", "            Inactiveuser "); Userdevice Existsdevice = _authenticationservice.getuserdevicE (Nowuser.userid, devicetype);//Session.queryover<userdevice> (). Where (x = X.accountid = = Nowaccount.id && X.devicetype = = DeviceType).            Singleordefault (); if (Existsdevice = = null) {string passkey = Md5cryptoprovider.getmd5hash (Nowuser.userid + nowus Er. LoginName + DateTime.UtcNow.ToString () + Guid.NewGuid ().                ToString ());  Existsdevice = new Userdevice () {UserId = Nowuser.userid, createtime = Datetime.utcnow, Activetime = datetime.utcnow, ExpiredTime = DateTime.UtcNow.AddM                Inutes (timeout), DeviceType = DeviceType, SessionKey = passkey};            _authenticationservice.adduserdevice (Existsdevice);                } else {existsdevice.activetime = Datetime.utcnow; Existsdevice.expiredtime = DateTime.UtcNow.AddMinutes (timeout);                _authenticationservice.updateuserdevice (Existsdevice);            } Nowuser.password = "";        return new Sessionobject () {SessionKey = Existsdevice.sessionkey, LogonUser = Nowuser}; }    }

API authentication

Authentication of identity information is implemented through the Actionfilter of the Web API, and each API request that requires authentication requires the client to pass a sessionkey over the URL.

Here we use a custom Sessionvalidateattribute to authenticate the client, which inherits from the System.Web.Http.Filters.ActionFilterAttribute, Add this attribute to each apicontroler that needs to be authenticated so that all actions under the controller will have the ability to authenticate, and there will be a small number of APIs that do not require authentication. This will do some exclusions, in order to keep the article clear, this will be explained in the following chapters.

public class SessionValidateAttribute:System.Web.Http.Filters.ActionFilterAttribute {public Const string Sess        Ionkeyname = "SessionKey";        Public Const string LogonUsername = "LogonUser"; public override void OnActionExecuting (Httpactioncontext filtercontext) {var qs = Httputility.parsequer            Ystring (FilterContext.Request.RequestUri.Query);            String sessionkey = Qs[sessionkeyname]; if (string.            IsNullOrEmpty (SessionKey)) {throw new Apiexception ("Invalid Session.", "invalidsession"); } Iauthenticationservice AuthenticationService = Iocmanager.intance.reslove<iauthenticationservice&gt            ;();            Validate user session var usersession = Authenticationservice.getuserdevice (SessionKey); if (usersession = = null) {throw new Apiexception ("SessionKey not Found", "requireparameter_sess            Ionkey ");            } else{//todo: If the session is expired (Usersession.expiredtime < Datetime.utcnow)                throw new Apiexception ("Session Expired", "sessiontimeout");                var logonUser = Authenticationservice.getuser (Usersession.userid);                if (LogonUser = = null) {throw new Apiexception ("User not Found", "Invalid_user"); } else {Filtercontext.controllercontext.routedata.values[logo                    Nusername] = LogonUser;                Setprincipal (New userprincipal<int> (LogonUser));                } usersession.activetime = Datetime.utcnow;                Usersession.expiredtime = DateTime.UtcNow.AddMinutes (60);            Authenticationservice.updateuserdevice (usersession);             }} private void Setprincipal (IPrincipal principal) {Thread.CurrentPrincipal = principal; if (HttpContext.Current! = null) {HttpContext.Current.User = principal; }        }    }

Onactionexcuting Method:

This is done before entering an action to check, this time we can take out sessionkey to Userdevice table in the same requestquerystring to do the query, to verify the authenticity of sessionkey to achieve the purpose of authentication.

User's Expiration Time:

When each API is accessed, the expiration time of the session (that is, Userdevice) is automatically updated to ensure that the SessionKey does not expire, and if it is not updated for a long time, the next access expires and needs to be logged in again for processing.

Request.isauthented:

The last section of the code above is setprincipal to set the user identity information in our thread context and HttpContext context, where we implement our own user identity type

public class Useridentity<tkey>: IIdentity {public useridentity (iuser<tkey> user) {                if (user! = null) {isauthenticated = true; UserId = user.                UserId; Name = user.                Loginname.tostring (); DisplayName = user.            DisplayName;        }} public string AuthenticationType {get {return ' customauthentication ';}        Public TKey UserId {get; private set;}        public bool IsAuthenticated {get; private set;}        public string Name {get; private set;}    public string DisplayName {get; private set;} } public class Userprincipal<tkey>: IPrincipal {public Userprincipal (useridentity<tkey> identit        Y) {identity = identity;        Public Userprincipal (iuser<tkey> user): This (new useridentity<tkey> (user)) {     }//<summary>   </summary> public useridentity<tkey> Identity {get; private set;}        IIdentity iprincipal.identity {get {return Identity;}        } bool IPrincipal.IsInRole (string role) {throw new NotImplementedException ();        }} public interface iuser<t> {T UserId {get; set;}        String LoginName {get; set;}    String DisplayName {get; set;} }

This guarantees that we can get the user information of the current thread context anywhere in the system, through HttpContext.User or System.Threading.Thread.CurrentPrincipal, so that it is easy to use everywhere

The following product-related APIs are added after authentication:

[Routeprefix ("Api/products"), Sessionvalidate] public class Productcontroller:apicontroller {[HttpGet]        public void Productsapi () {}///<summary>//Product paging data access//</summary> <returns></returns> [HttpGet, Route ("Product/getlist")] public page<product> Getprodu        Ctlist (String sessionkey) {return new page<product> (); }///<summary>//Get a single product///</summary>//<param name= "ProductId" ></p aram>//<returns></returns> [HttpGet, Route ("Product/get")] public product Getproduc        T (string sessionkey, Guid productId) {return new Product () {productId = productId}; }///<summary>//Add products///</summary>//<param name= "Product" ></param >//<returns></returns> [HttpPost, RouTe ("Product/add")] public Guid addproduct (string sessionkey, product product) {return GUID.NEWGU        ID (); }///<summary>//New products//</summary>/<param name= "ProductId" ></par  am>//<param name= "Product" ></param> [HttpPost, Route ("Product/update")] public void  UpdateProduct (String sessionkey, Guid productId, product product) {}///<summary>// Delete products///</summary>//<param name= "ProductId" ></param> [Httpdelete, Route ("Produ Ct/delete ")] public void deleteproduct (string sessionkey, Guid productId) {}

You can see that our productcontroller is topped with sessionvalidateattribute, the first position of each action parameter, plus a string SessionKey placeholder, This is primarily to allow swagger.net to generate test windows on the UI.

This article does not use the authorization mechanism such as OAuth, but simply implements the login authorization, which is suitable for small project use.

Here also only to achieve the system login, API access security, and does not guarantee the absolute security of the API system, we can intercept the HTTP messages on the route, intercept our API requests, intercept passwords and other login information, so we also need to add SSL certificate to our API, to achieve HTTPS encrypted transmission.

In addition, in the previous days there are seen combined with the client IP address and so on mixed generation sessionkey to do security, but also has certain limitations, the kind of solution appropriate, or according to their actual project situation to determine.

Due to time, this article only introduced the API user login and access authentication from the principle aspect, because this part of the real test design to the database interaction, the IOC and other infrastructure support, so this code can only appear in Swaggerui, but can not actually test the interface. I'll refine this part in the next code.

Code: Code Download (code hosted in CSDN codes)

"WEB API Project Combat Dry Series"-API Login and authentication (iii)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.