Børre Stenseth
Moduler>Websites>Flerbrukssider>Login

Loginn

Hva
Image1
En innloggingsrutine

Denne modulen tar for seg en ganske typisk innloggingssekvens. Vi ser for oss en situasjon der det ikke er noe poeng å holde noen ute, men vi vil at brukeren skal finne igjen sine data når  han/hun kommer inn. Fokus er ikke på sikkerhet.

Scenariet er slik at brukeren får beskjed om å logge inn som:

  • kjent bruker
  • ny bruker
  • gammel bruker som har glemt passordet

For å hjelpe brukeren dersom han glemmer passordet, får han tilbud om å spare tre verdier: fødselsår, postnummer og lykketall. Hva dette er, tekst eller tall, er det samme.

Passordene lagres i en enkel XML-struktur:

<?xml version="1.0" encoding="utf-8"?>
<users>
  <user name="ole" pwd="olsen" tag1="46" tag2="1784" tag3="7" />
  <user name="kari" pwd="karlsen07" tag1="23" tag2="2090" tag3="12" />
</users>

Alle de aktuelle dialogfragmentene er laget som Views innenfor en MultiView. Vi kan si at hvert View beskriver en tilstand i logginnsekvensen, og vi kan lage et tilstandsdiagram som planleggings- og dokumentsajonshjelpemiddel.

login1

Webside

<%@ Page Language="C#" AutoEventWireup="true"  
         CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Registrering</title>
    <link  rel="Stylesheet" type="text/css" href="StyleSheet.css" />
<script language="javascript" type="text/javascript">
// <!CDATA[
function Button5_onclick() {
document.getElementById('show_password').innerHTML=
    document.getElementById('hidden_password').innerHTML;
 return false;
}
// ]]>
</script>
</head>
<body>
  <asp:Label ID="LabelHeader" runat="server" 
             Text="Velkommen til dette vevstedet" 
             CssClass="mainheader"></asp:Label>
 <form id="form1" runat="server">
    <div>    
        
        <asp:MultiView ID="MultiView1" runat="server">
            
            <!-- ******************** introduction *********************** -->
            <asp:View ID="View1" runat="server">
                <fieldset>
                <legend>Du må registrere deg</legend>
                <div>
                    <br />
                    Jeg er allerede registrert:<br />
                </div>
                <div>
                    <br />
                Navn: &nbsp; &nbsp;&nbsp;<input id="Text1" type="text"  
                       runat="server" style="width: 168px; height: 16px" />
                    <asp:Label ID="BadNameIntro" 
                               runat="server" CssClass="errormsg" Width="226px">
                     </asp:Label>
                </div>
               <div>
                   <br />
                Passord:&nbsp;<input id="Password1" type="password"  
                    runat="server" style="width: 167px" />
                   <asp:Label ID="BadPwdIntro" 
                              runat="server" CssClass="errormsg" Width="226px">
                              </asp:Label><br />
                   <br />
                <input style="margin-left:200px" id="Button1" 
                runat="server" type="button" value="Slipp meg inn" 
                onserverclick="Button1_ServerClick" /><br />
                </div>
                <br />
                <hr />
                <br />
                <input id="Button2" type="button"  
                runat="server" value="Jeg er ny, registrer meg"  
                onserverclick="Button2_ServerClick" />
                <br />
                <br />
                <input id="Button3" type="button"  
                runat="server" value="Jeg har glemt passordet" 
                onserverclick="Button3_ServerClick" />
                </fieldset>
             </asp:View>
             
             
             
           <!-- ******************** handle new user  ***************** -->  
           <asp:View ID="View2" runat="server">
               <fieldset>
                    <legend>Registrering av ny bruker</legend>
                   <br />
                   Navn: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
                   &nbsp; &nbsp;<input id="Text2" type="text" 
                   runat="server" style="width: 145px" />
                   <asp:Label ID="BadName" runat="server" 
                   CssClass="errormsg" Width="226px"></asp:Label><br />
                   Passord: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
                   <input id="Password2" style="width: 147px" type="password" 
                   runat="server" />
                   <asp:Label ID="BadPwd" runat="server" 
                   CssClass="errormsg" Width="229px"></asp:Label><br />
                   
                   Gjenta passord:&nbsp;<input id="Password3" 
                   style="width: 148px" type="password" /><br />
                   <div class="msg">Hvis du fyller ut de 3 
                   feltene nedenfor kan du få hjelp
                   hvis du glemmer passordet</div>
                   Fødselsår: &nbsp; &nbsp; &nbsp;&nbsp;
                   <input id="Text3" style="width: 52px" type="text"  
                   runat="server"/><br />
                   Postnummer: &nbsp;&nbsp;
                   <input id="Text4" style="width: 54px" type="text" 
                   runat="server" /><br />
                   Lykketall: &nbsp; &nbsp; &nbsp; &nbsp;
                   <input id="Text5" style="width: 53px" type="text"  
                   runat="server"/><br />
                        <input id="Submit1" type="submit" 
                        value="Registrer meg" runat="server" 
                        onserverclick="Submit1_ServerClick"/><br />
               </fieldset>
            </asp:View>
            
            
            
           <!-- *************** handle forgetfull user  ********** --> 
           <asp:View ID="View3" runat="server">
              <fieldset>
                    <legend>Hjelp for å komme inn</legend>
                  <br />
                  &nbsp;&nbsp; Fødselsår: &nbsp; &nbsp; &nbsp;&nbsp;
                  <input id="Text6" style="width: 52px" type="text"  
                  runat="server"/><br />
                  &nbsp;&nbsp;
                  Postnummer: &nbsp;&nbsp;
                  <input id="Text7" style="width: 54px" type="text" 
                  runat="server" /><br />
                  &nbsp;&nbsp;
                  Lykketall: &nbsp; &nbsp; &nbsp; &nbsp;
                  <input id="Text8" style="width: 53px" type="text"  
                  runat="server"/><br />
                  <input style="margin-left:200px" id="Submit2" 
                  type="submit" value="Finn meg"  runat="server" 
                  onserverclick="Submit2_ServerClick"/>&nbsp;
                  <br />
               </fieldset>
           </asp:View>
           
           
           
           <!-- ************ You are inside ************* --> 
           <asp:View ID="View4" runat="server">
              <fieldset>
                    <legend>Du er registrert og logget inn</legend>
                  <br />
                  &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;
                  <asp:Label ID="SuccessName" runat="server" Text="Label">
                  </asp:Label><br />
                  <br />
                  <asp:Button ID="Button6" runat="server" Text="Logg ut" 
                  OnClick="Button6_Click" /></fieldset>
           </asp:View>
            
            
            
           <!-- ************* log in failed ************ -->  
           <asp:View ID="View5" runat="server">
           <fieldset>
                <legend>Beklager</legend>&nbsp;<br />
               Finner deg ikke
               <asp:Label ID="userName" runat="server" 
               Text="Label"></asp:Label><br />
               <br />
               &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
                <input id="Button4" type="button" 
                runat="server" value="OK" 
                onserverclick="Button4_ServerClick" />
           </fieldset>
           </asp:View>
           
           
           
           <!-- *************** already exist *************** --> 
            <asp:View ID="View6" runat="server">
           <fieldset>
                <legend>Finnes allerede</legend>
               <br />
               <span style="color: #0046d5">
               En bruker med dette navnet finnes allerede:<br />
                   <br />
               </span>
                <input id="Submit3" type="submit" value="Prøv igjen" 
                runat="server" onserverclick="Submit3_ServerClick"  />
               &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
                <input id="Submit4" type="submit" value="Gir opp" 
                runat="server" onserverclick="Submit4_ServerClick"  />
               <br />
           </fieldset>
           
           
           
           <!-- ************ confirmed help ************* --> 
            </asp:View>
            <asp:View ID="View7" runat="server">
           <fieldset>
                <legend>Du er funnet</legend>
               <asp:label style="display:none" ID="hidden_password" 
               runat="server"></asp:label>
               <asp:Label ID="username2" runat="server" Text="Label">
               </asp:Label>
               &nbsp;&nbsp;
                Passordet ditt er: &nbsp;&nbsp;
               
               <span id="show_password">
               <input id="Button5" type="button" value="Vis" 
               onclick="return Button5_onclick()" />
               </span>
               <br /><br />
               <input id="Submit5" type="submit" runat="server" value="OK" 
               onserverclick="Submit5_ServerClick" />
            </fieldset>
            </asp:View>
            
            
           
        </asp:MultiView>
       </div>
   </form>
</body>
</html>

Programkode

Default.aspx.cs

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.IO;

    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
                MultiView1.SetActiveView(View1);
            
            // reset all errormessages
            BadNameIntro.Text = "";
            BadPwdIntro.Text = "";
            BadName.Text = "";
            BadPwd.Text = "";
            
            // set filepath for passwordadmin
            pasadmin.setFileName( String.Format(@"{0}\App_Data\users.xml",
                           Path.GetDirectoryName(Request.PhysicalPath)));
            
            // check cookies
            HttpCookie c=Request.Cookies["user"];
            if(c!=null)
            {
                SuccessName.Text = c.Value; 
                MultiView1.SetActiveView(View4);
                return;
            }
        }
        protected void setCookie(String name)
        {
            HttpCookie cook = new HttpCookie("user");
            cook["Navn"] = name;
            Response.Cookies.Add(cook);
        }
        protected void killCookie()
        {
            HttpCookie cook = new HttpCookie("user");
            cook.Expires = DateTime.Now.AddDays(-1d);
            Response.Cookies.Add(cook);
        }

        protected void Button1_ServerClick(object sender, EventArgs e)
        {
            // slipp meg inn
            String name = Text1.Value;
            String pwd = Password1.Value;
            // control
            if (name.Length == 0)
            {
                BadNameIntro.Text = "mangler navn";
                return;
            }
            if (pwd.Length == 0)
            {
                BadPwdIntro.Text = "mangler passord";
                return;
            }
            if (pasadmin.OldUserOk(name, pwd))
            {
                // du er inne:
                SuccessName.Text = name;
                setCookie(SuccessName.Text);
                MultiView1.SetActiveView(View4);
            }
            else
            {
                // sorry
                MultiView1.SetActiveView(View5);
            }
        }
        protected void Button2_ServerClick(object sender, EventArgs e)
        {
            // new user, register me
            MultiView1.SetActiveView(View2);
        }
        protected void Button3_ServerClick(object sender, EventArgs e)
        {
            // forgotten the password, help him
            MultiView1.SetActiveView(View3);
        }
        protected void Button4_ServerClick(object sender, EventArgs e)
        {
            // user did not get inn and has received a message
            MultiView1.SetActiveView(View1);
        }
        protected void Submit1_ServerClick(object sender, EventArgs e)
        {
            // user submit application as new user
            String Name = Text2.Value;
            String Pwd1 = Password2.Value;
            String Pwd2 = Password2.Value;
            String Hlp1 = Text3.Value;
            String Hlp2 = Text4.Value;
            String Hlp3 = Text5.Value;
            // control
            if (Name.Length == 0)
            {
                BadName.Text = "mangler navn";
                return;
            }
            if ((Pwd1.Length < 3) || 
                (Pwd2.Length < 3) || 
                (Pwd1.CompareTo(Pwd2) != 0))
            {
                BadPwd.Text = "to identiske passord, lenger enn 3 tegn";
                return;
            }
            // user exists already, we pretend name identity
            // but is really name and password identity
            if (pasadmin.OldUserOk(Name, Pwd1))
            {
                // sorry already registered
                MultiView1.SetActiveView(View6);
                return;
            }
            String res = pasadmin.RegisterUser(Name, Pwd1, Hlp1, Hlp2, Hlp3);
            if (res != null)
            {
                SuccessName.Text = Name;
                setCookie(SuccessName.Text);
                MultiView1.SetActiveView(View4);
            }
        }
        protected void Submit2_ServerClick(object sender, EventArgs e)
        {
            // attempt to localize user based on the three fields
            String Hlp1 = Text6.Value;
            String Hlp2 = Text7.Value;
            String Hlp3 = Text8.Value;
            String[]NP = pasadmin.FindUser(Hlp1, Hlp2, Hlp3);
            if (NP == null)
            {
                userName.Text="?";
                MultiView1.SetActiveView(View5);
                return;
            }
            // found him, ok let him in
            String Pwd = NP[0];
            String Name = NP[1];
            hidden_password.Text = Pwd;
            username2.Text = Name;
            MultiView1.SetActiveView(View7);
        }
        protected void Submit3_ServerClick(object sender, EventArgs e)
        {
            // try again after having submitted existing data
            MultiView1.SetActiveView(View2);
        }
        protected void Submit4_ServerClick(object sender, EventArgs e)
        {
            // give up after having submitted existing data
            MultiView1.SetActiveView(View1);
        }
        protected void Submit5_ServerClick(object sender, EventArgs e)
        {
            // user is told he is found, and shown the password
            // let him in
            SuccessName.Text = username2.Text;
            setCookie(SuccessName.Text);
            MultiView1.SetActiveView(View4);
        }
        protected void Button6_Click(object sender, EventArgs e)
        {
            // want to log out
            killCookie();
            MultiView1.SetActiveView(View1);
        }
}

pasadmin.cs

Administrasjon av passordfila er lagt til en egen klasse, pasadmin. Denne kan lett byttes ut. Klassen har følgende rutiner som brukes utenfra, fra Dafault.aspx.cs: RegisterUser, FindUser, OldUserOk, setFileName.

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml;
using System.IO;

    /// <summary>
    /// Summary description for pasadmin
    /// </summary>
    public class pasadmin
    {
        static String FileName;
        public pasadmin(String filename)
        {
        }
        public static void setFileName(String fn)
        {
            // set filename from usercode, since usercode knows the path ?
            FileName=fn;
        }
        static String GetXmlFileName()
        {
            return FileName;
        }
        static XmlDocument GetUserDoc()
        {
            XmlDocument doc = new XmlDocument();
            try
            {
                String FileName = GetXmlFileName();
                doc.Load(FileName);
                return doc;
            }
            catch (Exception ex)
            {
                // errormessage 
                return null;
            }
        }
        static void SetUserDoc(XmlDocument doc)
        {
            try
            {
                String FileName = GetXmlFileName(); 
                FileStream fs = new FileStream(FileName, FileMode.Open);
                XmlTextWriter writer = 
                    new XmlTextWriter(fs, System.Text.Encoding.UTF8);
                writer.Formatting = Formatting.Indented;
                doc.WriteContentTo(writer);
                writer.Flush();
                writer.Close();
            }
            catch (Exception ex)
            {
                // errormessage                 
            }
        }
        static public bool OldUserOk(String name, String passwd)
        {
            XmlDocument doc = GetUserDoc();
            if (doc == null)
                return false;
            XmlNodeList users = doc.GetElementsByTagName("user");
            foreach (XmlElement user in users)
            {
                String name_att = user.GetAttribute("name");
                String pwd_att = user.GetAttribute("pwd");
                if ((name_att.CompareTo(name.Trim()) == 0) && 
                    (pwd_att.CompareTo(passwd.Trim()) == 0))
                    return true;
            }
            return false;
        }
        static public String[] FindUser(String Hlp1, String Hlp2, String Hlp3)
        {
            XmlDocument doc = GetUserDoc();
            if (doc == null)
                return null;
            XmlNodeList users = doc.GetElementsByTagName("user");
            foreach (XmlElement user in users)
            {
                String t1 = user.GetAttribute("tag1");
                String t2 = user.GetAttribute("tag2");
                String t3 = user.GetAttribute("tag3");
                if ((t1.CompareTo(Hlp1.Trim()) == 0) &&
                    (t2.CompareTo(Hlp2.Trim()) == 0) &&
                    (t3.CompareTo(Hlp3.Trim()) == 0))
                {
                    String[] L = new String[2];
                    L[0] = user.GetAttribute("pwd");
                    L[1] = user.GetAttribute("name");
                    return L;
                }
            }
            return null;
        }
        static public String RegisterUser(String Name, String Pwd, 
            String Hlp1, String Hlp2, String Hlp3)
        {
            // set nonempty values
            if (Hlp1.Length == 0)
                Hlp1 = "_no_value_at_all";
            if (Hlp2.Length == 0)
                Hlp2 = "_no_value_whatsoever";
            if (Hlp3.Length == 0)
                Hlp3 = "_no_value_here";
            XmlDocument doc = GetUserDoc();
            if (doc == null)
                return null;
            XmlElement new_user = doc.CreateElement("user");
            new_user.SetAttribute("name", Name.Trim());
            new_user.SetAttribute("pwd", Pwd.Trim());
            new_user.SetAttribute("tag1", Hlp1.Trim());
            new_user.SetAttribute("tag2", Hlp2.Trim());
            new_user.SetAttribute("tag3", Hlp3.Trim());
            doc.DocumentElement.AppendChild(new_user);
            SetUserDoc(doc);
            return "ok";
        }
    }

Cookies

Løsnongen setter en cookie når brukeren er godkjent og fjerner den samme cookien når brukeren logger ut. Koden for å sette cookie er slik, fra Default.aspx.cs:

protected void setCookie(String name)
{
    HttpCookie cook = new HttpCookie("user");
    cook["Navn"] = name;
    Response.Cookies.Add(cook);
}

Koden for å fjerne samme cookie er slik, også fra Default.aspx.cs:

protected void killCookie()
{
    HttpCookie cook = new HttpCookie("user");
    cook.Expires = DateTime.Now.AddDays(-1d);
    Response.Cookies.Add(cook);
}

Inputkontroll

Løsningen har en rudimentær inputkontroll på tjeneren. Det vil være en klar forbedring å legge en bedre inputkontroll på klientsiden.

Referanser
Prosjekt:
https://svn.hiof.no/svn/psource/Csharpsites/demosite6

En tilsvarende rutine skrevet i Python/CGI er beskrevet her: http://www.it.hiof.no/~borres/ml/login/p-login.html . I dette eksempelet er HTML-fragmentene samlet i en HTML-fil som Pythonskriptet plukker fra.

Vedlikehold

B.Stenseth, januar 2007

(Velkommen) Moduler>Websites>Flerbrukssider>Login (Inputkontroll)