WebAPI using ActionFilterAttribute to implement token token authentication and permissions control of action

Source: Internet
Author: User

. NET WebAPI using ActionFilterAttribute to implement token token authentication and permissions control on action

Project background is a community-class app (for the light spit ... ), Bo Master mainly responsible for backstage business and interface. I have not played webapi before, but the leader has to use this (specific reason to know), had to bite the bullet.

Recently just finished permission this piece, share out to everybody. Welcome all kinds of spit groove critical trample ...

First of all, the identification of the user identity, simply made a token mechanism. User login, background generate token, issue token, user carry token access ...

1.cache Management class, Because the blogger uses the Httpruntime.cache to store Token,iis restart or unexpectedly shut down, etc. will cause the cache to empty, had to do in the database cache backup, when the cache is empty to query the database for cache data, there is the cache was accidentally emptied, need to re-put In the cache.

<summary>///cache management///token, user credentials, and expiration time relationship data in cache///</summary> public class CacheManager {
private static readonly Itempcacheservice Tempcacheservice = Servicelocator.instance.getservice<itempcacheservi Ce> (); <summary>///Initialize the cache data structure///</summary>//Token token///UUID User ID Voucher/// Usertype User class//timeout expires///<remarks>//</remarks> private static void C Acheinit () {if (httpruntime.cache["PASSPORT. TOKEN "] = = null) {DataTable dt = new DataTable (); Dt. Columns.Add ("token", Type.GetType ("System.String")); Dt. columns["token"]. Unique = true; Dt. Columns.Add ("UUID", Type.GetType ("System.Object")); Dt. columns["UUID"]. DefaultValue = null; Dt. Columns.Add ("Usertype", Type.GetType ("System.String")); Dt. columns["Usertype"]. DefaultValue = null; Dt. Columns.Add ("Timeout", Type.GetType ("System.DateTime")); Dt. Columns["Timeout"]. DefaultValue = DateTime.Now.AddDays (7); Datacolumn[] keys = new datacolumn[1]; Keys[0] = dt. columns["token"]; Dt. PrimaryKey = keys; var tempcaches = tempcacheservice.getallcaches (); if (Tempcaches.any ()) {foreach (var tempcachedtoshow in tempcaches) {DataRow dr = dt. NewRow (); dr["token"] = Tempcachedtoshow.usertoken; dr["uuid"] = Tempcachedtoshow.useraccountid; dr["usertype"] = tempCacheDTOShow.UserType.ToString (); dr["Timeout"] = Tempcachedtoshow.endtime; Dt. Rows.Add (DR); The expiration time for//cache is the token expiration of HttpRuntime.Cache.Insert ("PASSPORT. TOKEN ", DT, NULL, DateTime.MaxValue, Timespan.fromdays (7 * 2)); }}///<summary>///get user UUID ID//</summary>//<param name= "token" ></param>//<returns>&lt ;/returns> public static Guid Getuuid (String token) {cacheinit (); DataTable dt = (DataTable) httpruntime.cache["PASSPORT. TOKEN "]; datarow[] dr = dt. Select ("token = '" + token + "'"); if (Dr. Length > 0) {return new Guid (dr[0]["UUID"]. ToString ()); } return guid.empty; }///<summary>///Get user category (divided into employee, enterprise, customer service, administrator, etc.)///</summary>//<param Name= "token" ></param>///<returns></returns> public static string Getusertype (string Token) {cacheinit (); DataTable dt = (DataTable) httpruntime.cache["PASSPORT. TOKEN "]; datarow[] dr = dt. Select ("token = '" + token + "'"); if (Dr. Length > 0) {return Dr[0]["Usertype"]. ToString (); } return null; }///<summary>////To determine if a token exists///</summary>//<param name= "token" > Token </param> <returns></returns> public static bool Tokenisexist (string token) {Cache Init (); DataTable dt = (DataTable) httpruntime.cache["PASSPORT. TOKEN "]; datarow[] dr = dt. Select ("token = '" + token + "'"); if (Dr. Length > 0) {var timeout = datetime.parse (dr[0]["Timeout"]. ToString ()); if (Timeout > DateTime.Now) {return true; } else {Removetoken (token); return false; }} return false; }///<summary>//Remove a token///</summary>//<param name= "token" ></param& Gt /<returns></returns> public static bool Removetoken (string token) {cacheinit (); DataTable dt = (DataTable) httpruntime.cache["PASSPORT. TOKEN "]; datarow[] dr = dt. Select ("token = '" + token + "'"); if (Dr. Length > 0) {dt. Rows.remove (Dr[0]); } return true; }///<summary>//Update token expiration///</summary>//<param name= "token" > Token </p aram>//<param Name= "Time" > Expiration </param> public static void Tokentimeupdate (string token, Da Tetime time) {cacheinit (); DataTable dt = (DataTable) httpruntime.cache["PASSPORT. TOKEN "]; datarow[] dr = dt. Select ("token = '" + token + "'"); if (Dr. Length > 0) {dr[0]["timeout"] = time; }}///<summary>///Add token///</summary><param name= "token" > Token </param>//<param name= "UUID" > User ID Voucher </param>//<par Am Name= "usertype" > User category </param>//<param name= "Timeout" > Expiry time </param> public static VO ID Tokeninsert (String token, object uuid, string usertype, DateTime timeout) {cacheinit (); Token does not exist then add if (! Tokenisexist (token)) {datatable dt = (DataTable) httpruntime.cache["PASSPORT. TOKEN "]; DataRow dr = dt. NewRow (); dr["token" = token; dr["uuid"] = UUID; dr["usertype"] = usertype; dr["Timeout"] = timeout; Dt. Rows.Add (DR); Httpruntime.cache["PASSPORT. TOKEN "] = DT; Tempcacheservice.add_tempcaches (New list<tempcachedto_add> () {New Tempcachedto_ad D () {EndTime = timeout, Useraccountid = new Guid (UUID. ToString ()), usertoken = new Guid (token), usertype = (usertype) enum.parse (ty Peof (usertype), usertype)}); }//token exists update expiration time else {tokentimeupdate (token, timeout); Tempcacheservice.update_tempcaches (token), timeout); } } }

2. The next step is to verify the token that is carried by the user, which is implemented by inheriting ActionFilterAttribute, which also takes into account the anonymous Access API, which allows anonymous access (without login access) for some APIs. So, first write a attribute that stands for anonymity:

    <summary>    ///Anonymous access tag    ///</summary> [AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)] public    class Anonymousattribute:attribute    {    }

Then click on the [Anonymous] tab for the action that allows anonymous access, and then see our token Verification code:

    <summary>///User Token authentication///</summary> public class Tokenprojectorattribute:actionfilterattribute        {Private Const string usertoken = "token"; Private readonly Iaccountinfoservice Accountinfoservice = Servicelocator.instance.getservice<iaccountinfoservice        > (); Private readonly Itempcacheservice Tempcacheservice = servicelocator.instance.getservice<itempcacheservice> ()        ; public override void OnActionExecuting (Httpactioncontext actioncontext) {//anonymous access verification var anony            Mousaction = actioncontext.actiondescriptor.getcustomattributes<anonymousattribute> (); if (!anonymousaction.any ()) {//verify token var token = tokenverification (actioncont            EXT); } base.        OnActionExecuting (Actioncontext); }///<summary> Identity token Authentication///</summary>//<param name= "Actioncontext" &GT;&L     T;/param>   Protected virtual string tokenverification (Httpactioncontext actioncontext) {//Get token V            AR token = GetToken (actioncontext.actionarguments, ActionContext.Request.Method); Determine if token is valid if (!            Cachemanager.tokenisexist (token)) {throw new Userloginexception ("token has expired, please re-login!");            }//Determine if the user is frozen if (Accountinfoservice.exist_user_isforzen (Accounthelper.getuuid (token)))                {Cachemanager.removetoken (token);                Tempcacheservice.delete_onetempcaches (token);            throw new Userloginexception ("This user has been frozen, please contact customer service!");        } return token; } private String GetToken (dictionary<string, object> actionarguments, HttpMethod type) {VA            R token = "";               if (type = = Httpmethod.post) {foreach (var value in actionarguments.values) {     token = value. GetType (). GetProperty (usertoken) = = null? GetToken (Actionarguments, Httpmethod.get): value. GetType (). GetProperty (usertoken). GetValue (value).                ToString (); }} else if (type = = Httpmethod.get) {if (!actionarguments.containskey (Us                Ertoken) {throw new Exception ("token! not attached"); } if (Actionarguments[usertoken]! = NULL) {token = Actionarguments[usert Oken].                ToString ();                } else {throw new Exception ("token cannot be empty!");            }} else {throw new Exception ("No other Access available!");        } return token; }    }

Here's an explanation of the GetToken method:

1. Bloggers only do the post and get method verification, other requests are not used and do not do, welcome to add

The callback in 2.POST mode is a case where the POST request interface has only one simple parameter, such as the following interface:

        <summary>////        manually push SMS to new users///</summary>//        <returns></returns>        [ HttpPost]        [Route ("Api/common/pushnewusersms")]public pushnewworksmsresult pushnewusersms ([frombody]string Token)        {            sendmessagesservice.pushnewusersms ();            return new Pushnewworksmsresult () {Code = 0};        }

Of course, the Post method will generally write parameters into a class, for a parameter situation, bloggers do not like to do so. In this case, you need the Ajax commit space-time variable name to get:

    Push new user Marketing SMS    function pushnewusersms () {        $ (". Tuiguang"). Unbind ("click");
Note the following argument is null "" $.post (Config.Api.Common.PushNewUserSMS, {"": $.cookie ("Mpcbtoken")}, function (data) { if ( Data. Code = = 0) { alert ("Sent successfully!"); _initdatas (); } else { Config.Method.JudgeCode (data, 1);}} ); }

In this way, we only need to play the [Tokenprojector] tab on each controller, and then the [Anonymous] tab on the Allow anonymous action will make it easy to get token verification done.

3. In addition to token verification, we also want to control the action of the user role, such as an action to get the balance of the user's wallet (a), must only employees, enterprises can access, the administrator, customer service does not have a wallet, so access is not allowed, The business should be to access another action (B) that gets the balance of the specified user's wallet, which, of course, does not open permissions to employees or businesses. This involves the need to implement a control action access to the function, we have to verify the user token, then get token to get the user basic information (including the role), then only need to do a permission annotation to the action can solve the problem, Let's start by writing a attribute that represents permission control:

    <summary>    ///rights control tag    ///</summary> [AttributeUsage (AttributeTargets.Method, inherited = True, AllowMultiple = True)] public    class Moduleauthorizationattribute:attribute    {        public Moduleauthorizationattribute (params string[] authorization)        {this            . authorizations = authorization;        }        <summary>///Allow access to roles///        </summary> public        string[] authorizations {get; set;}    }

On each action that requires permission control, click on the [Moduleauthorization] tab and indicate the Access role:

        <summary>///Get wallet Balance///</summary>//<param name= "token" ></param&        Gt <returns></returns> [HttpGet] [Route ("Api/account/getwalletbalance")] [Moduleauthoriz            ation (new[] {"Staff", "Enterprise"})] public getwalletbalanceresult getwalletbalance (string token) {            var result = This.walletService.Get_Wallet_Balance (Accounthelper.getuuid (token));        return new Getwalletbalanceresult () {Code = 0, Balance = result}; }///<summary>//admin//Process withdrawal request///</summary>//<param name= "Handletempwithdrawalsmodel" ></param>///<returns></returns> [HttpPost] [Route ( "Api/account/handletempwithdrawals")] [Moduleauthorization (new[] {"Platformcustomer"})] public HANDLETEMPW Ithdrawalsresult HandletempwithdrawalS ([frombody] Handletempwithdrawalsmodel Handletempwithdrawalsmodel) {walletservice.handle_t  Empwithdrawals (Accounthelper.getuuid (Handletempwithdrawalsmodel.token), Handletempwithdrawalsmodel.message,            Handletempwithdrawalsmodel.tempid, handletempwithdrawalsmodel.issuccess);        return new Handletempwithdrawalsresult () {Code = 0}; }

Then we modify tokenprojectorattribute this class, after verifying token to do authorization authentication, the permission authentication method is as follows:

        <summary>///Action access verification///</summary>//        <param name= "token" > Identity token </param >//        <param name= "Actioncontext" ></param>//        <returns></returns>        protected virtual void Authorizecore (string token, Httpactioncontext actioncontext)        {            //Permissions control action Verify            var Moduleauthorizationaction = Actioncontext.actiondescriptor.getcustomattributes<moduleauthorizationattribute > ();            if (Moduleauthorizationaction.any ())            {                var userrole = accounthelper.getusertype (token);                if (!moduleauthorizationaction[0]. Authorizations.contains (Userrole.tostring ()))                {                    throw new Exception ("User illegal cross-access, token:" + token);                }            }        }

OK, finally, it realizes the authentication of the user token and action permission Webapi.

Of course, Bo Master is just contact with WEBAPI, and business needs are simpler, if there is no fault, welcome to point out, we must humbly ask.

Category: Web API

WebAPI using ActionFilterAttribute to implement token token authentication and permissions control of action

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.