Images handler with resizing options in C#.Net

Posted by Ruben Canton on March 2, 2012 at 9:00 am
categories Web programming

First have a look at my post for how to make an Images Handler. And from there, let’s continue.

The idea is that if I request something like these:

  • http://localhost:54086/images/v/?img=500667&w=540
  • http://localhost:54086/images/v/?img=500667&h=200
  • http://localhost:54086/images/v/?img=500667&w=540&maxh=90
  • http://localhost:54086/images/v/?img=500667&w=540&h=200&maxh=90&maxw=100

It will resize my image to the size I set and also, it will check the size limit for heights or widths so the resulting resized image doesn’t break our layout.

Adding some params to resize the image

Lets add the querystring params to the handler:

        public const String PARAM_WIDTH = "w";
        public const String PARAM_HEIGHT = "h";
        public const String PARAM_MAXWIDTH = "maxw";
        public const String PARAM_MAXHEIGHT = "maxh";

And a condition method:

        private Boolean NeedsToBeResized(Image img) {
            // If one of the params comes most probably Ill need to resize:
            if (request.QueryString[PARAM_WIDTH] != null) { return true; }
            if (request.QueryString[PARAM_HEIGHT] != null) { return true; }
            if (request.QueryString[PARAM_MAXWIDTH] != null) { return true; }
            if (request.QueryString[PARAM_MAXHEIGHT] != null) { return true; }
            return false;
        }

Resizing the image

Returning a resized Image Method

        private void ReturnResizedImage(Image img, String filename) {
            try {
                // Getting params from querystring:
                Size newSize = new Size(0, 0);
                Size maxSize = new Size(0, 0);
                if (request.QueryString[PARAM_WIDTH] != null) { newSize.Width = int.Parse(request.QueryString[PARAM_WIDTH]); }
                if (request.QueryString[PARAM_HEIGHT] != null) { newSize.Height = int.Parse(request.QueryString[PARAM_HEIGHT]); }
                if (request.QueryString[PARAM_MAXWIDTH] != null) { maxSize.Width = int.Parse(request.QueryString[PARAM_MAXWIDTH]); }
                if (request.QueryString[PARAM_MAXHEIGHT] != null) { maxSize.Height = int.Parse(request.QueryString[PARAM_MAXHEIGHT]); }

                img = resizeImage(img, CalculateNewSize(img, newSize, maxSize));
                img.Save(HttpContext.Current.Response.OutputStream, getFormat(filename));
            }
            catch (Exception e) {
                response.StatusCode = 400;
                response.Write("Bad request.");
            }
        }

Checking the new size for the image

        private static Size CalculateNewSize(Image img, Size newSize, Size max) {
            float nPercent = 1; float nPercentW = 1; float nPercentH = 1;

            // STEP 1. RESIZE TO FIX SIZES
            if (newSize.Width > 0 && newSize.Height > 0) {
                // The smaller gets priority:
                if (img.Width != newSize.Width) nPercentW = ((float)newSize.Width / (float)img.Width);
                if (img.Height != newSize.Height) nPercentH = ((float)newSize.Height / (float)img.Height);
                if (nPercentH < nPercentW) { nPercent = nPercentH; } else { nPercent = nPercentW; }
            } else if (newSize.Width > 0) {
                nPercent = ((float)newSize.Width / (float)img.Width);
            } else if (newSize.Height > 0) {
                nPercent = ((float)newSize.Height / (float)img.Height);
            }

            // Calculate new sizes:
            int resWidth = (int)(img.Width * nPercent);
            int resHeight = (int)(img.Height * nPercent);

            // ==================================
            // STEP 2. CHECK THE LIMITS
            if (max.Width > 0 && resWidth > max.Width) {
                nPercent = ((float)max.Width / (float)resWidth);
                resWidth = (int)(resWidth * nPercent);
                resHeight = (int)(resHeight * nPercent);
            }
            if (max.Height > 0 && resHeight > max.Height) {
                nPercent = ((float)max.Height / (float)resHeight);
                resWidth = (int)(resWidth * nPercent);
                resHeight = (int)(resHeight * nPercent);
            }

            return new Size(resWidth, resHeight);
        }

Resizing the Image, simple way

        private static Image resizeImage(Image imgToResize, Size size) {
            if (imgToResize.Width != size.Width || imgToResize.Height != size.Height) {
                return new Bitmap(imgToResize, size.Width, size.Height);
            } else {
                return imgToResize;
            }
        }

Getting the format type

Unfortunately, to send the image to the client in the response we need to know its format type, which we can know in various ways like checking the image filename extension or getting its mimetype. Affortunately, both of us were saved in the db:

        private static System.Drawing.Imaging.ImageFormat getFormat(String MimeType) {
            switch (MimeType.ToLower()) {
                case "image/jpeg":
                case "image/jpg": return System.Drawing.Imaging.ImageFormat.Jpeg;
                case "image/gif": return System.Drawing.Imaging.ImageFormat.Gif;
                case "image/png": return System.Drawing.Imaging.ImageFormat.Png;
                default: return System.Drawing.Imaging.ImageFormat.Bmp;
            }
        }

In case you prefer to use the filename:

    private static System.Drawing.Imaging.ImageFormat getFormat(String name) {
        switch (System.IO.Path.GetExtension(name).ToLower()) {
            case ".jpeg":
            case ".jpg": return System.Drawing.Imaging.ImageFormat.Jpeg;
            case ".gif": return System.Drawing.Imaging.ImageFormat.Gif;
            case ".png": return System.Drawing.Imaging.ImageFormat.Png;
            default: return System.Drawing.Imaging.ImageFormat.Bmp;
        }
    }

The new Image Handler ProcessRequest

        public void ProcessRequest(HttpContext context) {
            request = context.Request;
            response = context.Response;

            List<SqlParameter> pl = new List<SqlParameter>();
            pl.Add(new SqlParameter("imgId", request.QueryString["img"]));
            IDataReader dr = MyNamespace.db.getReader("sp_getImage", pl);

            if (dr != null && dr.Read()) {
                context.Response.ContentType = dr["mimeType"].ToString();
                MemoryStream ms = new MemoryStream((byte[])dr["image"]);
                Image img = System.Drawing.Image.FromStream(ms);

                if (!NeedsToBeResized(img)) { //Display directly from db:
                    context.Response.BinaryWrite((byte[])dr["image"]);
                } else {
                    ReturnResizedImage(img, dr["fileName"].ToString());
                }
            } else {
                response.StatusCode = 404;
                response.Write("Not found.");
            }
        }

Finally, putting all of it together:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

namespace MyNamespace {
    public class VirtualImagesHandler : IHttpHandler {

        private HttpRequest request = null;
        private HttpResponse response = null;

        public const String PARAM_WIDTH = "w";
        public const String PARAM_HEIGHT = "h";
        public const String PARAM_MAXWIDTH = "maxw";
        public const String PARAM_MAXHEIGHT = "maxh";

        public bool IsReusable { get { return true; } }
        public void ProcessRequest(HttpContext context) {
            request = context.Request;
            response = context.Response;

            //
            // TODO: Check if user has rights to access this image.
            //

            List<SqlParameter> pl = new List<SqlParameter>();
            pl.Add(new SqlParameter("imgId", request.QueryString["img"]));
            IDataReader dr = MyNamespace.db.getReader("sp_getImage", pl);

            if (dr != null && dr.Read()) {
                context.Response.ContentType = dr["mimeType"].ToString();
                MemoryStream ms = new MemoryStream((byte[])dr["image"]);
                Image img = System.Drawing.Image.FromStream(ms);

                if (!NeedsToBeResized(img)) { //Display directly from db:
                    context.Response.BinaryWrite((byte[])dr["image"]);
                } else {
                    ReturnResizedImage(img, dr["fileName"].ToString());
                }
            } else {
                response.StatusCode = 404;
                response.Write("Not found.");
            }
        }

        private Boolean NeedsToBeResized(Image img) {
            // If one of the params comes most probably Ill need to resize:
            if (request.QueryString[PARAM_WIDTH] != null) { return true; }
            if (request.QueryString[PARAM_HEIGHT] != null) { return true; }
            if (request.QueryString[PARAM_MAXWIDTH] != null) { return true; }
            if (request.QueryString[PARAM_MAXHEIGHT] != null) { return true; }
            return false;
        }

        private void ReturnResizedImage(Image img, String filename) {
            try {
                // Getting params from querystring:
                Size newSize = new Size(0, 0);
                Size maxSize = new Size(0, 0);
                if (request.QueryString[PARAM_WIDTH] != null) { newSize.Width = int.Parse(request.QueryString[PARAM_WIDTH]); }
                if (request.QueryString[PARAM_HEIGHT] != null) { newSize.Height = int.Parse(request.QueryString[PARAM_HEIGHT]); }
                if (request.QueryString[PARAM_MAXWIDTH] != null) { maxSize.Width = int.Parse(request.QueryString[PARAM_MAXWIDTH]); }
                if (request.QueryString[PARAM_MAXHEIGHT] != null) { maxSize.Height = int.Parse(request.QueryString[PARAM_MAXHEIGHT]); }

                img = resizeImage(img, CalculateNewSize(img, newSize, maxSize));
                img.Save(HttpContext.Current.Response.OutputStream, getFormat(response.ContentType));
            }
            catch (Exception e) {
                response.StatusCode = 400;
                response.Write("Bad request.");
            }
        }

        private static System.Drawing.Imaging.ImageFormat getFormat(String MimeType) {
            switch (MimeType.ToLower()) {
                case "image/jpeg":
                case "image/jpg": return System.Drawing.Imaging.ImageFormat.Jpeg;
                case "image/gif": return System.Drawing.Imaging.ImageFormat.Gif;
                case "image/png": return System.Drawing.Imaging.ImageFormat.Png;
                default: return System.Drawing.Imaging.ImageFormat.Bmp;
            }
        }

        private static Image resizeImage(Image imgToResize, Size size) {
            if (imgToResize.Width != size.Width || imgToResize.Height != size.Height) {
                return new Bitmap(imgToResize, size.Width, size.Height);
            } else {
                return imgToResize;
            }
        }

        private static Size CalculateNewSize(Image img, Size newSize, Size max) {
            float nPercent = 1; float nPercentW = 1; float nPercentH = 1;

            // STEP 1. RESIZE TO FIX SIZES
            if (newSize.Width > 0 && newSize.Height > 0) {
                // The smaller gets priority:
                if (img.Width != newSize.Width) nPercentW = ((float)newSize.Width / (float)img.Width);
                if (img.Height != newSize.Height) nPercentH = ((float)newSize.Height / (float)img.Height);
                if (nPercentH < nPercentW) { nPercent = nPercentH; } else { nPercent = nPercentW; }
            } else if (newSize.Width > 0) {
                nPercent = ((float)newSize.Width / (float)img.Width);
            } else if (newSize.Height > 0) {
                nPercent = ((float)newSize.Height / (float)img.Height);
            }

            // Calculate new sizes:
            int resWidth = (int)(img.Width * nPercent);
            int resHeight = (int)(img.Height * nPercent);

            // ==================================
            // STEP 2. CHECK THE LIMITS
            if (max.Width > 0 && resWidth > max.Width) {
                nPercent = ((float)max.Width / (float)resWidth);
                resWidth = (int)(resWidth * nPercent);
                resHeight = (int)(resHeight * nPercent);
            }
            if (max.Height > 0 && resHeight > max.Height) {
                nPercent = ((float)max.Height / (float)resHeight);
                resWidth = (int)(resWidth * nPercent);
                resHeight = (int)(resHeight * nPercent);
            }

            return new Size(resWidth, resHeight);
        }

        public static String getImageURL(int ImageID) {
            return SkyGuard.CSC.Config.PATH_VIRTUALIMGFOLDER + "?img=" + ImageID;
        }
        public static String getImageURL(int ImageID, ImageSizes sizes) {
            String url = SkyGuard.CSC.Config.PATH_VIRTUALIMGFOLDER + "?img=" + ImageID;
            if (sizes.Width > 0) { url += "&" + PARAM_WIDTH + "=" + sizes.Width.ToString(); }
            if (sizes.Height > 0) { url += "&" + PARAM_HEIGHT + "=" + sizes.Height.ToString(); }
            if (sizes.MaxWidth > 0) { url += "&" + PARAM_MAXWIDTH + "=" + sizes.MaxWidth.ToString(); }
            if (sizes.MaxHeight > 0) { url += "&" + PARAM_MAXHEIGHT + "=" + sizes.MaxHeight.ToString(); }

            return url;
        }

        public class ImageSizes {
            public int Width { get; set; }
            public int Height { get; set; }
            public int MaxWidth { get; set; }
            public int MaxHeight { get; set; }

            public ImageSizes() : this(-1, -1, -1, -1) { }
            public ImageSizes(int pWidth, int pHeight) {
                if (pWidth > 0) Width = pWidth;
                if (pHeight > 0) Height = pHeight;
                MaxHeight = -1;
                MaxWidth = -1;
            }
            public ImageSizes(int pWidth, int pHeight, int pMaxWidth, int pMaxHeight) {
                if (pWidth > 0) Width = pWidth;
                if (pHeight > 0) Height = pHeight;
                if (pMaxWidth > 0) MaxWidth = pMaxWidth;
                if (pMaxHeight > 0) MaxHeight = pMaxHeight;
            }
        }

    }
}
 

Uploading an image to database in C#

Posted by Ruben Canton on February 28, 2012 at 12:31 pm
categories Web programming

1. Placing the FileUpload object

First, we need to set the FileUpload object, we will use the one .Net gives us:

    <asp:FileUpload ID="myFile" runat="server" />

That was easy :)

2. Getting the file from the FileUpload object

2.1 Checking the uploaded file is an image

Before going on, I want to show you this useful function you will need later:

        public Boolean IsImage(HttpPostedFile pf) {
            Boolean res = false;

            switch (pf.ContentType) {
                case "image/gif":
                case "image/jpeg":
                case "image/jpg":
                case "image/bmp":
                case "image/png":
                case "image/pjpeg":
                case "image/x-png":
                    res = true;
                    break;
                default:
                    res = false;
                    break;
            }

            if (!res) { //If the filetype doesnt work i try with the extension:
                switch (Path.GetExtension(pf.FileName)) {
                    case "gif":
                    case "jpeg":
                    case "jpg":
                    case "bmp":
                    case "png":
                        res = true; break;
                    default: break;
                }
            }

            return res;
        }

2.2 Checking Im uploading something

I like to have these two useful methods:

        private Boolean IsUploadingAnImage() {
            return (myFile.PostedFile != null && myFile.PostedFile.FileName != "");
        }

        private void UploadPhoto() {
            MyNamespace.Uploads.UploadProfileImage(myFile); // A call to a class that will do the stuff (see below)
            // Do more stuff if necessary
        }

So I can do this:

        if (IsUploadingAnImage()) { UploadPhoto(); }

2.3 Getting the file

To get the file in the object you need a byte array to get the input, then you can use that array to save it into the db, to create a file and save it in disk or to create an image object and play with it before doing something else. Lets see:

// Getting the object into a byte array:
byte[] fileData = new byte[Uploader.PostedFile.ContentLength]; //We make a byte array with the file size.
Uploader.PostedFile.InputStream.Read(fileData, 0, (int)Uploader.PostedFile.ContentLength); //we read the file into our array.

Saving it into the database

Putting all of it together and using a stored that saves the image into db with its type.

        public void UploadProfileImage(FileUpload Uploader) {
            if (IsImage(Uploader.PostedFile)) {

                byte[] fileData = new byte[Uploader.PostedFile.ContentLength]; //We make a byte array with the file size.
                Uploader.PostedFile.InputStream.Read(fileData, 0, (int)Uploader.PostedFile.ContentLength); //we read the file into our array.

                List<SqlParameter> pl = new List<SqlParameter>();
                pl.Add(new SqlParameter("image", fileData));
                pl.Add(new SqlParameter("mimeType", Uploader.PostedFile.ContentType));

                IDataReader dr = MyNamespace.db.getReader("sp_UploadImage", pl);
                if (dr != null && dr.Read()) {
                    if (dr[0].ToString().ToUpper() == "OK") {
                        ImageID = (int)dr[1]; // I could get the new image id in db, for example.
                    }
                }

            } else {
                ErrorMessage = "File must be an image.";
            }
        }
 

Validate forms in client side using jQuery

Posted by Ruben Canton on February 24, 2012 at 9:00 am
categories Web programming, Web security

There is a quick way for validating forms if you are using jQuery.

1. Download the validation plugin

You need to download the jQuery Validate plugin. Alternatively you can make a call to the online version from your code.

2. Add the plugin to your website

I presume you are yet using the latest jQuery library and you don’t need any explanation on how to use it, then, just add another reference to the plugin in your code so you can use it:

    <script src='Scripts/jquery.-1.7.1.min.js' type='text/javascript'></script>
    <script src='Scripts/jquery.validate.min.js' type='text/javascript'></script>

3. Make a call to validation

Now, if you just want to validate a form using default validation you only need to make a call to this function:

<script type="text/javascript" language="javascript">
    $(document).ready(function () {
        $('form').validate();
    });
</script>

You can of course have more forms and select the one you want to validate etc. But lets simplify it for this example. Now, the form will be validated but since the rules are not set jQuery will not know what to validate.

4. Adding rules to validation

To add rules you only need to add style classes to the class atribute like this:

Name <input class="required" type="text" > <br />
Website <input class="required url" type="text" > <br />
Phone <input class="number" type="text" > <br />
Email <input class="required email" type="text" > <br />

As you can see, Ive add some classes and just doing that the form will be validated and the input fields be checked with the conditions Ive added through the classes. You can add multiple conditions to make a field required and number, for example.

Here is a list of some of the class styles you can use:

  • required
  • email
  • number (decimal)
  • digits (integer)
  • date
  • dateISO
  • url
  • creditcard

You can also add some properties like minlength, maxlength or range:

Name <input class="required" type="text" minlength="2"> <br />
Website <input class="required url" type="text" maxlength="80"> <br />
Phone <input class="number" type="text" range="600"> <br />
Email <input class="required email" type="text" > <br />

And that will help where adding classes wouldn’t work (you need to set a value). A list of them:

  • minlength
  • maxlength
  • rangelength
  • min
  • max
  • range
  • accept (file extensions)

5. Customizing validation

But despite thats so useful, quick and flexible you may need more specific conditions or just want to add your own error messages. For doing so its still very easy when you make the call to the validate function, just adding custom values:

    $('form').validate({
        rules: {
            txtName: required,
            website: {required: true, minlength: 5},
            phone: {required:true,
                    digits: true,
                    rangelength: [6, 9]
            },
            email {required: true}
        }, messages: {
            txtName: required : 'The name is required',
            txtSurname: { required: 'The website is required',
                          minlength: 'The website need to be at least 5 characters length'}
            phone { rangelength: 'The phone needs to be between 6 and 9 characters' }
        }
    });

You can add individual conditions without brakets like in name, or add more conditions using brackets. To make them match the fields you have to add the name property to them:

Name    <input name="name" class="required" type="text" minlength="2"> <br />
Website <input name="website" class="required url" type="text" maxlength="80"> <br />
Phone   <input name="phone" class="number" type="text" range="600"> <br />
Email    <input name="email" class="required email" type="text" > <br />

6. Customizing messages style

Error messages will show a label like this one:

<label class="error" for="txtName" generated="true"></label>

You can add a style in your stylespage or in the same page to change its look and make it fit your page better. Notice you can use the class .error, but also the property generated=”true” or the property “for” so that you can specify more properly in your css:

.error{} /*general error messages*/
.error[generated=true] {} /*generated error msgs when jQuery validates */
.error[for=txtName]{} /*very custom style for error msg when txtName is not correct*/

You can check more options, methods, etc. at its documentation page.

 

Building your Authentication system in .Net4.0

Posted by Ruben Canton on February 20, 2012 at 10:30 am
categories Web programming, Web security

By default, .Net applications offer a prebuilt authentication system that you can use to give some privacy to your website in case its a small one. But, in case you pretend to use your existing DB with its existing users table and your existing conditions you may want to build your own authentication system.

Most of these can be built using a standard .Net format which Im going to show:

Web.config

Let’s start talking about the webconfig file, since as its name indicates, its the file were the site configuration resides and then the best place to configure the site authentication. You can of course build your own manual system just setting something at the master page or at any individual page, but you can save some time just learning to use the web config.

Web.config Authentication tag

First, let’s just say we can add four types of authentication to our website. One based in windows (so, in IIS and its OS users), another based in Microsoft Passport service and finally the one based in web forms. Normally, and as most of webpages in the net, you will use a typical web form based authentication (the one with the user/password boxes and the login button).

So, that’s what we add to webconfig under system.web tag:

<authentication mode="Forms"><forms loginUrl="~/login.aspx" timeout="2880"/></authentication>

Notice the “loginUrl” property at the forms tag, you will set on there the location of the login page in case the user tries to access a forbidden page. Pages that require authentication will redirect the user here automatically, no need to code anything.

Web.config Authorization

Now, we need to set the authorization level for the whole page. This means if we want to make it an intranet or a public website (with maybe some private areas).

For doing so, we’ll use the authentication tag under the system.web tag and set the level of authentication needed to request the website in general. We can use multiple options but most probably you will need to know only these ones:

    <system.web>
        <compilation debug="true" targetFramework="4.0"></compilation>
        <authorization>
                <deny users="*"/> <!-- Denies permission to anyone, website closed. -->
                <deny users="?"/> <!-- Denies permission to non-authenticated users. Closed to anonymous users. You use this for an intranet. -->
                <deny allow="*"/> <!-- Website open to everybody. You use this for a public website. -->
        </authorization>
        <authentication mode="Forms"><forms loginUrl="~/login.aspx" timeout="2880"/></authentication>

        <pages theme="Default"/>
    </system.web>

You have to add only one of these deny/allow tags, the one you think fits better.

Web.config locations

After doing that, you can add individual auth. rights for different folders or files, like login.aspx or scripts/ folder. In case your website is open to public most of its folders are too, but if you set it as an intranet have in mind that, if you don’t open to public some files and folders the ones who are not authenticated will not be able to authenticate due to forbidden access to login.aspx, and they could not see the styles or run the scripts if they have no access to the needed folders. So, you will need to add something like this under the configuration tag:

<configuration>
    <location path="login.aspx"><system.web><authorization><allow users="*"/></authorization></system.web></location>
    <location path="scripts"><system.web><authorization><allow users="?"/></authorization></system.web></location>
    <location path="imgs"><system.web><authorization><allow users="?"/></authorization></system.web></location>
    <location path="App_Themes"><system.web><authorization><allow users="?"/></authorization></system.web></location>
</configuration>

If your site is open to public you may use something like this instead:

<configuration>
    <location path="admin"><system.web><authorization><deny users="?"/></authorization></system.web>
    <location path="privateArea"><system.web><authorization><deny users="?"/></authorization></system.web></location>
</configuration>

And that’s all you need to know about webconfig. You can search more info in Google if you need or just continue forward.

User class

Now you should build a basic User class to manage your website users. I mean, if you are managing authorization and private areas in the website you sure have some way of storing those users data and, normally, that is done in a database using a Users table or similar. Here is a posible idea of how that basic User class could look like:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Data.SqlClient;

namespace MyNameSpace {
    public class User {

        //Basic
        public int ID { get; set; }
        public String Username { get; set; }
        public String PasswordInMD5 { get; set; }
        public MyNameSpace.PermissionRol Permissions { get; set; }

        //Details
        public String Email { get; set; }
        public String FirstName { get; set; }
        public String LastName { get; set; }
        public String Phone { get; set; }

        public User() {
            Initialize();
        }
        public User(Boolean loadFromCookie) {
            Initialize();
            if (loadFromCookie) {
                this.LoadUser(MyNameSpace.AuthCookie.GetUser()); //getting basic params from cookie
                this.LoadUser(getUser(Username, PasswordInMD5)); // getting details from db
            }
        }

        private void Initialize() {
            ID = 0;
            Username = "";
            PasswordInMD5 = "";
            Permissions = new MyNameSpace.PermissionRol();

            FirstName = "";
            LastName = "";
            Email = "";
            Phone = "";
        }

        public static User getUser(String username, String pass) {
            List<SqlParameter> pl = new List<SqlParameter>();
            pl.Add(new SqlParameter("userName", username));
            pl.Add(new SqlParameter("MD5password", pass));

            User u = new User();
            IDataReader dr = MyNameSpace.db.getReader("sp_getUserDetails", pl);
            if (dr != null && dr.Read()) {
                u.ID = (int)dr["userId"];
                u.Username = dr["userName"].ToString();
                u.PasswordInMD5 = dr["userPassword"].ToString();
                u.FirstName = dr["firstName"].ToString();
                u.LastName = dr["lastName"].ToString();
                u.Phone = dr["contactNumber"].ToString();
                u.Email = dr["contactEmail"].ToString();
                u.Permissions.Load(MyNameSpace.PermissionRol.getRol((int)dr["RoleId"]));
            }
            return u;
        }

        /// <summary>
        /// Loads user details from DB having its id.
        /// </summary>
        public void LoadUser(MyNameSpace.User newUser) {
            this.ID = newUser.ID;
            this.PasswordInMD5 = newUser.PasswordInMD5;
            this.Username = newUser.Username;
            this.FirstName = newUser.FirstName;
            this.LastName = newUser.LastName;
            this.Email = newUser.Email;
            this.Phone = newUser.Phone;
        }

    }

}

Let’s not discuss its properties, its just an example. You can copypaste and adapt it to your needs. It also includes a reference to a PermissionRoles class where I have the different user rights and options (so, I do not only give access to a page, but also to do different actions or visualize different items). I give you an idea of how to implement it:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Data.SqlClient;
using System.Web.Caching;

namespace MyNameSpace {
    public class PermissionRol {

        //Basic
        public int ID { get; set; }
        public String Name { get; set; }

        //Permissions
        public Boolean UserView;
        public Boolean UserAdd;
        public Boolean UserEdit;
        public Boolean UserRemove;

        public Boolean UnitView;
        public Boolean UnitAdd;
        public Boolean UnitEdit;
        public Boolean UnitRemove;
        public Boolean UnitAssignation;

        public Boolean AdminRights;
        public Boolean EnableEditMode;

        public PermissionRol() {
            ID = 0;
            Name = "";

            UserView = false;
            UserAdd = false;
            UserEdit = false;
            UserRemove = false;

            UnitView = false;
            UnitAdd = false;
            UnitEdit = false;
            UnitRemove = false;
            UnitAssignation = false;

            EnableEditMode = false;
            AdminRights = false;
        }

        public void Load(PermissionRol newRol) {
            this.ID = newRol.ID;
            this.Name = newRol.Name;

            this.UserView = newRol.UserView;
            this.UserAdd = newRol.UserAdd;
            this.UserEdit = newRol.UserEdit;
            this.UserRemove = newRol.UserRemove;

            this.UnitView = newRol.UnitView;
            this.UnitAdd = newRol.UnitAdd;
            this.UnitEdit = newRol.UnitRemove;
            this.UnitRemove = newRol.UnitRemove;
            this.UnitAssignation = newRol.UnitAssignation;

            this.EnableEditMode = newRol.EnableEditMode;
            this.AdminRights = newRol.AdminRights;
        }

        public static List<PermissionRol> getRoles() {
            // Try to get from cache:
            List<PermissionRol> lstRoles = (List<PermissionRol>)HttpRuntime.Cache.Get(MyNameSpace.Config.CACHE_PERMISSIONROLES);

            if (lstRoles == null) {
                lstRoles = new List<PermissionRol>();
                IDataReader dr = MyNameSpace.db.getReader("sp_getRoles");

                if (dr != null) {
                    while (dr.Read()) {
                        PermissionRol rol = new PermissionRol();
                        rol.ID = (int)dr["ID"];
                        rol.Name = dr["Name"].ToString();

                        rol.EnableEditMode = (Boolean)dr["EnableEditMode"];
                        rol.UnitAdd = (Boolean)dr["UnitAdd"];
                        rol.UnitAssignation = (Boolean)dr["UnitAssignation"];
                        rol.UnitEdit = (Boolean)dr["UnitEdit"];
                        rol.UnitRemove = (Boolean)dr["UnitRemove"];
                        rol.UnitView = (Boolean)dr["UnitView"];
                        rol.UserAdd = (Boolean)dr["UserAdd"];
                        rol.UserEdit = (Boolean)dr["UserEdit"];
                        rol.UserRemove = (Boolean)dr["UserRemove"];
                        rol.UserView = (Boolean)dr["UserView"];
                        rol.AdminRights = (Boolean)dr["AdminRights"];

                        lstRoles.Add(rol);
                    }
                }

                //Add to cache
                HttpRuntime.Cache.Remove(MyNameSpace.Config.CACHE_PERMISSIONROLES);
                HttpRuntime.Cache.Add(MyNameSpace.Config.CACHE_PERMISSIONROLES, lstRoles, null, DateTime.Now.AddMinutes(15), Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.High, null);
            }

            return lstRoles;
        }

        public static PermissionRol getRol(int pID) {
            IEnumerable<PermissionRol> rol = from roles in getRoles() where roles.ID == pID select roles;
            return rol.ToList<PermissionRol>()[0];
        }

    }
}

Authentication Cookie

Now its time to get to next stage and build our authentication cookie. This is a special type of cookie that .Net uses to authenticate the user and make sure this user is authenticated. Which will be the difference between an anonymous user and a known one. Be care with this then since not any cookie will do. You may create your own encrypted cookie and use to it authenticate but .Net will still not recognize that user as authenticated and due to your webconfig confs the user will have no access.

So, let’c build our own Authentication cookie adapted to our needs in our own class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;

namespace MyNameSpace {
    public class AuthCookie {

        public AuthCookie() {
            //
            // TODO: Add constructor logic here
            //
        }

        public static MyNameSpace.User GetUser() {
            MyNameSpace.User u = new MyNameSpace.User();
            HttpCookie au = HttpContext.Current.Request.Cookies.Get(FormsAuthentication.FormsCookieName);
            if (au != null) {
                FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(au.Value);

                if (!ticket.Expired) {
                    String data = ticket.UserData;
                    u.Username = data.Split('|')[0];
                    u.PasswordInMD5 = data.Split('|')[1];
                } else {
                    LogOut();
                }
            }
            return u;
        }

        public static void LogOut() {
            FormsAuthentication.SignOut();
            HttpContext.Current.Session.Abandon();
            HttpContext.Current.Response.Redirect("~/login.aspx");
        }

        /// <summary>
        /// Creates the authentication cookie.
        /// </summary>
        public static void Save(MyNameSpace.User u) {
            Save(u, false);
        }

        /// <summary>
        /// Creates the authentication cookie.
        /// </summary>
        /// <param name="u">User</param>
        /// <param name="isPersistent">Default: false.</param>
        public static void Save(MyNameSpace.User u, Boolean isPersistent) {
            DateTime expirationDate = DateTime.MaxValue;
            if (isPersistent) { expirationDate = DateTime.Now.AddMonths(3); }

            String userData = u.Username + "|" + u.PasswordInMD5;

            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, "CSC", DateTime.Now,
                expirationDate, isPersistent, userData, FormsAuthentication.FormsCookiePath);

            // Encrypt the ticket.
            string encTicket = FormsAuthentication.Encrypt(ticket);

            HttpContext.Current.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
        }

    }
}

This one is pretty simple, it has a method to Save the Cookie sending a User object (which we did before) and another to get it. Also, we can use it to LogOut so all the Login/Logout things are kept here. What I save in the Cookie is the username and password in MD5, I decided to go through this type of authentication for this test project, but of course you can use different ways of doing it (in fact, I tend to use different combinations).

Login Page

Finally, we have to set the code for the Login Page. Whatever the layout you use you will most probably end up using some user/pass combination. So this is it:

    public partial class Login : System.Web.UI.Page {
        protected void Page_Load(object sender, EventArgs e) {
            lbErrorMessage.Text = "";
        }

        protected void Page_PreRender(object sender, EventArgs e) {
            pnlErrorMessage.Visible = (lbErrorMessage.Text.Length > 0);
        }

        protected void BTNLogin_Click(object sender, EventArgs e) {
            MyNameSpace.User u = MyNameSpace.User.getUser(TXTUser.Text, getInMD5(TXTPass.Text));

            if (u.ID > 0) {
                MyNameSpace.AuthCookie.Save(u);
                Redirect();
            } else {
                lbErrorMessage.Text = "Invalid Username or Password.";
            }
        }

        private void Redirect() {
            if (Request.QueryString["ReturnUrl"] != null && Request.QueryString["ReturnUrl"].ToString().Length > 2) {
                Response.Redirect(Request.QueryString["ReturnUrl"]);
            } else {
                Response.Redirect("~/default.aspx");
            }
        }

        public static String getInMD5(String inputString) {
            byte[] input = Encoding.UTF8.GetBytes(inputString);
            byte[] output = MD5.Create().ComputeHash(input);
            StringBuilder sb = new StringBuilder(output.Length);
            for (int i = 0; i < output.Length; i++) {
                sb.Append(output[i].ToString("X2"));
            }
            return sb.ToString();
        }

    }

Accesing the User from any Page

We can then create this User object at our Master Page so that it loads on any request (in case we need this to be done) and access it from our pages. If you don’t know how to do this, you can check how to access a MasterPage object from any page with more detail.

Master Page Example:

        public MyNameSpace.User User;

        protected void Page_Init(object sender, EventArgs e) {
            User = new MyNameSpace.User(true);
        }

        protected void Page_Load(object sender, EventArgs e) {
            lbWelcomeMsg.Text = "You are logged in as " + User.Username;
        }

Default page example:

    public partial class Default1 : System.Web.UI.Page {
        MyNameSpace.User User;

        protected void Page_Load(object sender, EventArgs e) {
            User = ((MyNameSpace.MyMasterPage)Page.Master).User;
            lbUserName.Text = User.FirstName;
        }

    }
 

How to get a string in MD5 in C#.Net

Posted by Ruben Canton on February 17, 2012 at 9:22 am
categories Web programming, Web security

Here it is:

        public static String getInMD5(String inputString) {
            byte[] input = Encoding.UTF8.GetBytes(inputString);
            byte[] output = MD5.Create().ComputeHash(input);
            StringBuilder sb = new StringBuilder(output.Length);
            for (int i = 0; i < output.Length; i++) {
                sb.Append(output[i].ToString("X2"));
            }
            return sb.ToString();
        }

You may need this too:

using System.Text;
using System.Security.Cryptography;

WordPress Themes