In the last essay, "Web API Application Architecture design Analysis (1)", I have a broad analysis and design of the various application architectures of Web APIs, the Web API is an application interface framework that can build HTTP services to support a wider range of clients, including browsers, The framework of mobile devices such as mobile phones and tablets, this article continues this topic and describes how to use the ASP. NET Web API to design the Web API layer and related invocation processing.
1. Web API Interface Access classification
The way the Web API interfaces are accessed can be divided into several categories:
1) One is to use the user token, through the Web API interface for data access. This way, can effectively identify the user's identity, for the user interface to return user-related data, such as including user information maintenance, password modification, or user contacts and other user identity-related data.
2) One is to use a secure signature for data submission. The data submitted in this way, the URL connection signature parameters are secured by certain rules of encryption, the server received the data after the same rules of security encryption, verify that the data has not been tampered with, then the data modification processing. Therefore, we can specify different encryption keys for different access methods, such as Web/app/winfrom, but the secret key is agreed by both parties, and is not transmitted on the network connection, the connection transmission is generally the appid of this access, The server uses this AppID to perform cryptographic comparisons of signature parameters, which are similar to the callback processing mechanisms in the background, and they are handled in this way.
3) One way is to provide a public interface call, do not need to pass in the user token, or to encrypt the parameters of the signature, this interface is generally less, just provide some very regular data display.
The following illustration shows the description and approximate application scenarios for these types of access methods.
2. Implementation of WEB API using secure signature
First of all, we register for the user, we need to be approved by the terminal, that is, they need to carry out a secure signature, the background to confirm the validity of the signature, in order to achieve the normal user registration, or be forged data, the system lost its original meaning.
<summary>/// Registration User Information interface/// </summary> public interface Iuserapi {// < summary>/// registered user processing, including user name, password, ID number, cell phone and other information//</summary>// <param name= "JSON" > Registered User Information </param>// <param name= "signature" > Encrypted signature string </param>// <param name= "Timestamp" > Timestamp </param>// <param name= "nonce" > Random number </param>// <param name= "AppID" > Application access id</param> //<returns></returns> resultdata ADD (Userjson json, string Signature, string timestamp, string nonce, string appid); }
In fact, we obtain the user's token, also need to carry out user security signature authentication, so that we effectively ensure the legitimacy of user identity token acquisition.
<summary>////system authentication/// </summary> public interface Iauthapi { //< summary>/// registered user get access token interface///</summary>// <param name= "username" > User login name </param >// <param name= "password" > User password </param>// <param name= "signature" > Encrypted signature string </ param>// <param name= "timestamp" > Timestamp </param>// <param name= "nonce" > Random number </ param>// <param name= "AppID" > Application access id</param>// <returns></returns> Tokenresult Getaccesstoken (string Username, string password, string signature, string timestamp, string nonce, string appid); }
The parameters described above, we mention a few parameters, one is a cryptographic signature string, one is a timestamp, one is a random number, one is the application access ID, our general processing rules are as follows.
1) Web API for a variety of application access, such as the app, Web, WinForm and other access terminal allocation application AppID and communication key Appsecret, both sides of each store.
2) The access side should carry the following parameters when requesting the Web API interface: Signature, timestamp, nonce, AppID, signature is generated based on several parameters and encryption key.
3) When the Web API receives an interface call request, it must first check that the passed signature is legitimate, and then call the relevant interface after validation.
The processing logic for the cryptographic signature on the server side (Web API side) of the validation process reference interface is as follows.
1) Check whether the time difference between the timestamp and the system is within a reasonable time, such as 10 minutes.
2) dictionary ordering of three parameters of Appsecret, timestamp and nonce
3) concatenation of three parameter strings into a single string for SHA1 encryption
4) After the encrypted string can be compared with signature, if the match is identified that the request originated from an application, the request is legitimate.
The C # side code checksum is shown below.
<summary>///Check data integrity of application access///</summary>//<param name= "signature" > Plus Secret signature Content </param>//<param name= "timestamp" > Timestamp </param>//<param name= "nonce" > Random string & lt;/param>//<param name= "AppID" > Application access id</param>//<returns></returns> Public Checkresult validatesignature (string signature, string timestamp, string nonce, String appid) {C Heckresult result = new Checkresult (); result.errmsg = "Data integrity check does not pass"; For more information on access channels according to AppID AppInfo channelinfo = Bllfactory<app>. Instance.findbyappid (AppID); if (channelinfo! = null) {#region Verify that the source of the signature parameter is correct string[] arrtmp = {Channelinfo. Appsecret, timestamp, nonce}; Array.Sort (ARRTMP); String tmpstr = String. Join ("", arrtmp); TMPSTR = Formsauthentication.hashpasswordforstOringinconfigfile (Tmpstr, "SHA1"); Tmpstr = Tmpstr.tolower (); if (tmpstr = = Signature && validateutil.isnumber (timestamp)) {DateTime Dttime = Timestamp. ToInt32 (). Inttodatetime (); Double minutes = DateTime.Now.Subtract (dttime). Totalminutes; if (minutes > timspanexpiredminutes) {result.errmsg = "signature timestamp expires"; } else {result.errmsg = ""; Result.success = true; Result.channel = Channelinfo.channel; }} #endregion} return result; }
Once we have completed a successful authentication of the security signature, that is, we confirm the source and completeness of the data submission, we can do more and more security-related operations, such as the operation to obtain the user's access token information as shown below.
The first step is to verify that the user's signature meets the requirements, to match the user information, and to generate the user access token data JSON, which is returned to the caller.
3. Implementation of WEB APIs using security tokens
Through the above interface, we obtain the user access token, and then the user-related information calls, we can pass this token parameters can be passed, this token with the user's basic information, such as user ID, expiration time, etc., this token design idea from the JSON Web Token (JWT), specifically refer to http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html, as well as the items on GitHub https:// GITHUB.COM/JWT-DOTNET/JWT.
Because the invocation of the Web API is a stateless way of calling, we pass token to our user information, so we just need to verify token.
The token generation logic for JWT is as follows
After the token is generated, we need to verify the token before the Web API call processing to ensure that the token is valid.
The code to check is to reverse the process of token generation, to obtain the corresponding information, and to make valid judgments about the time of token issuance, it is generally possible to contract a failure time, such as 1 days or 7 days, and not set too short.
<summary>///Check user's token validity///</summary>//<param name= "token" >< /param>//<returns></returns> public checkresult Validatetoken (string token) { The returned result object Checkresult result = new Checkresult (); result.errmsg = "Token check does not pass"; if (!string. IsNullOrEmpty (token) {try {string decodedjwt = Jsonwebtoken . Decode (token, sharedkey); if (!string. IsNullOrEmpty (DECODEDJWT) {#region Check token object contents Dynamic Roo t = Jobject.parse (DECODEDJWT); string username = Root.name; string UserID = Root.iss; int jwtcreated = (int) Root.iat; Check the validity period of the token for a valid TimeSpan of 7 days t = (datetime.utcnow-new DateTime (1970, 1, 1)); int timestamp = (int) t.totaldays; if (timestamp-jwtcreated > Expireddays) {throw new Argumentexcepti On ("User token fails."); }//Successful check result.success = true; Result.errmsg = ""; Result.userid = userid; #endregion}} catch (Exception ex) {L Ogtexthelper.error (ex); }} return result; }
In general, the access token is not permanent, for the re-update of the access token, you can set a rule, only allow the latest token to use, and store it in the interface cache for comparison, when the application system exits, the memory of the token will be removed.
4. Development of ASP. NET Web API
Above we define the General Web API interface, and implement the corresponding business implementation, if we need to create a Web API layer, but also need to build a Web API project.
Once you have created the appropriate project, you can add a Web API base class for your project to facilitate control of common interfaces.
Then we can create more application API controllers on the controller directory.
Finally, to unify all API interfaces is to return JSON, we need to set the code inside the Webapiconfig.
public static class Webapiconfig {public static void Register (httpconfiguration config) { //Web API Configuration and Service CONFIG. Setcorspolicyproviderfactory (New Corspolicyfactory ()); Config. Enablecors (); Web API Routing config. Maphttpattributeroutes (); Config. Routes.maphttproute ( name: "Defaultapi", routetemplate: "Api/{controller}/{action}/{id}", defaults:new {action = "POST", id = routeparameter.optional} ); Remove the JSON formatter //config. Formatters.remove (config. Formatters.jsonformatter); Remove the XML formatter config. Formatters.remove (config. Formatters.xmlformatter); } }
5. Testing the Web API interface
The next thing we need to do is to add a business interface for specific testing, we recommend using the WinForm project, conducting a test on each interface, or considering the way you want to use unit tests to see people's preferences.
For example, if we want to test the user login interface, our test code is as follows.
<summary>///Generate signature string///</summary>//<param name= "Appsecret" > Access key &L t;/param>//<param name= "timestamp" > Timestamp </param>//<param name= "nonce" > Random number </param > Private String Signaturestring (string Appsecret, string timestamp, string nonce) {string[] Arrtmp = {Appsecret, timestamp, nonce}; Array.Sort (ARRTMP); String tmpstr = String. Join ("", arrtmp); Tmpstr = FormsAuthentication.HashPasswordForStoringInConfigFile (tmpstr, "SHA1"); return Tmpstr.tolower (); Private Tokenresult Gettokenresult () {string timestamp = DateTime.Now.DateTimeToInt (). ToString (); String nonce = new Random (). Nextdouble (). ToString (); String signature = signaturestring (Appsecret, timestamp, nonce); string appended = string. Format ("&signature={0}×tamp={1}&nonce={2}&appid={3}", signature, timestamp, nonce, appId); String queryurl = URL + "auth/getaccesstoken?username=test&password=123456" + appended; Httphelper helper = new Httphelper (); String token = helper. Gethtml (Queryurl); Console.WriteLine (token); Tokenresult Tokenresult = jsonconvert.deserializeobject<tokenresult> (token); return tokenresult; }
If we have already obtained the token, we are given the test processing code for the connection based on the token pass parameter and get additional data as shown below.
Get access token tokenresult Tokenresult = Gettokenresult (); String queryurl = URL + "/contact/get?token=" + Tokenresult.access_token; Httphelper helper = new Httphelper (); string result = Helper. Gethtml (Queryurl); Console.WriteLine (result);
If the post data is required, then the calling code is shown below.
Use the Post method var data = new { name = "Zhang San", certno = "123456789", }; var postdata = data. ToJson (); Queryurl = URL + "/contact/add?token=" + Tokenresult.access_token; Helper = new Httphelper (); Helper. ContentType = "Application/json"; result = Helper. Gethtml (Queryurl, PostData, true); Console.WriteLine (result);
The Web API will automatically convert the JSON data of the post to the corresponding object.
If it is a get method, we may be able to debug directly through the browser, if it is post, we need to use some assistance tools, such as Fiddler, but the best way is to get a test tool for your own needs, convenient testing.
Here is my own web API for the development of the needs of a dedicated debugging tool, can automatically assemble the relevant parameters, including the use of security signature parameters, but also all the parameter data can be stored.
Web API Interface Security Verification