C# 登录功能(优雅且详细)


前言

此系列文章是有关贵州省第一届商务软件解决方案技能大赛试题的求解,下附试题以及项目源码。

试题

项目源码


一、需求描述

  1. 制作一个登陆界面,包含验证码,记住密码以及根据登录用户类型(RoleID)加载不同界面的功能。
  2. 用户使用账号与密码登录系统。本系统的用户包括 3 种类型
  3. 若用户的登录失败次数达到 3 次,那么系统应显示并且同时包含字母与数字的4位验证码,验证码字符输入正确方可登录。
  4. 若选择记住密码,下次登录时直接显示上次输入的账号和密码

二、功能设计

1.登录界面设计

登录界面

2.数据库

获取登录id和password需要连接SQL server数据库,则需要创建一个用于链接数据库的类,在登录界面代码中调用。

SQLserver数据表结构:
数据表结构

3.登录

  1. 验证登录账号和密码
  2. 获取登录账号的类型(以数字代表类型,一共有三种类型,分别是1,2,3)
  3. 若验证错误次数超过三次,则生成验证码

4.记住账号

将账号信息储存到appconfig文件中

5.验证码

  1. 达到条件时创建验证码
  2. 生成验证码图片
  3. 验证码输入不正确或点击更新验证码

三、程序实现

1.创建一个SqlHelper的工具类,用于查询数据

有关数据库连接详细解析见下附链接
.Net连接SQL Server数据库的优雅方式(巨详细)

namespace OlympicManagementSystem.Util
{
    public class SqlHelper
    {
        public static string ConStr { get; set; }//数据库连接字符串
        public static DataTable ExecuteTable(string cmdStr)//获取数据表的方法,返回一个DataTable
        {
            using (SqlConnection con = new SqlConnection(ConStr))
            {
                con.Open();
                SqlCommand cmd = new SqlCommand(cmdStr, con);
                SqlDataAdapter adapter = new SqlDataAdapter(cmd);
                DataSet ds = new DataSet();
                adapter.Fill(ds);
                return ds.Tables[0];
            }
        }
        public static int ExecuteNonQuery(string cmdStr)//修改数据表的方法,返回受影响行数
        {
            using (SqlConnection con = new SqlConnection(ConStr))
            {
                con.Open();
                SqlCommand cmd = new SqlCommand(cmdStr, con);
                int rows = cmd.ExecuteNonQuery();
                if (rows <= 0)
                {
                    throw new Exception("Database operation failed");//操作失败抛出异常
                }
                return rows;
            }
        }
    }
}

2.验证登录信息功能的函数

从数据库查询登录信息,并储存账户类型(方便主窗体判断登录账户类型)

 private bool loginFlag()//Verify the user information,record roleID and return true or false
 {
     if (txbID.Text == "" || txbPwd.Text == "")
     {
         MessageBox.Show("用户名和密码不能为空", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
         return false;
     }
     else
     {//Query user information
         string sql = "select * from Staff where LoginID = '" + txbID.Text + "' and Password = '" + txbPwd.Text + "'";
         DataTable dataTable = SqlHelper.ExecuteTable(sql);
         if (dataTable.Rows.Count > 0)
         {
             DataRow dataRow = dataTable.Rows[0];
             roleID = (int)dataRow["RoleID"];
             Configuration cf = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
             cf.AppSettings.Settings["roleID"].Value = roleID.ToString();//record roleID
             cf.Save();
             return true;
         }
         else
         {
             MessageBox.Show("用户名或密码错误", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
             return false;
         }
     }
 }

3.实现验证码功能

写一个用于创建验证码的工具类

先创建验证码字符串,然后使用字符串生成图片

namespace OlympicManagementSystem.Util
{
    class VerificationCode
    {
        ///生成随机验证字符串
        public static string CreateRandomCode(int CodeLength)
        {
            int rand;
            char code;
            string randomCode = String.Empty;//随机验证码
            //生成特定长度的验证码
            Random random = new Random();
            for (int i = 0; i < CodeLength; i++)
            {
                rand = random.Next();
                if (rand % 3 == 1)
                {
                    code = (char)('A' + (char)(rand % 26));//随机取字母
                }
                else if (rand % 3 == 2)
                {
                    code = (char)('a' + (char)(rand % 26));
                }
                else
                {
                    code = (char)('0' + (char)(rand % 10));
                }
                randomCode += code.ToString();
            }
            return randomCode;
        }
        ///创建图片
        public static void CreateImage(string strValidCode, PictureBox pbox)
        {
            try
            {
                int RandAnlge = 45;//旋转角度
                int MapWidth = (int)(strValidCode.Length * 21);
                Bitmap map = new Bitmap(MapWidth, 28);//创建图片背景
                Graphics graph = Graphics.FromImage(map);
                graph.Clear(Color.AliceBlue);//清除话画面,填充背景颜色
                graph.DrawRectangle(new Pen(Color.Black, 0), 0, 0, map.Width - 1, map.Height - 1);//画一个边框
                graph.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;//模式
                Random rand = new Random();
                //背景噪点生成
                Pen blackPen = new Pen(Color.LightGray, 0);
                for (int i = 0; i <= 50; i++)
                {
                    int x = rand.Next(0, map.Width);
                    int y = rand.Next(0, map.Height);
                    graph.DrawRectangle(blackPen, x, y, 1, 1);
                }
                //验证码选装防止机器识别
                char[] chars = strValidCode.ToCharArray();//拆散字符串组成单字符数组
                //文字居中
                StringFormat format = new StringFormat(StringFormatFlags.NoWrap);
                format.Alignment = StringAlignment.Center;
                format.LineAlignment = StringAlignment.Center;
                //定义颜色
                Color[] c = { Color.Black, Color.Red, Color.DarkBlue, Color.Orange, Color.Brown, Color.DarkCyan, Color.Purple, Color.Green };
                //定义字体
                string[] font = { "Verdana", "Microsoft Sans Serif", "Comic Sans MS", "Arial", "宋体" };
                for (int i = 0; i < chars.Length; i++)
                {
                    int cindex = rand.Next(7);
                    int findex = rand.Next(5);
                    Font f = new System.Drawing.Font(font[findex], 13, System.Drawing.FontStyle.Bold);//字体样式,大小
                    Brush b = new System.Drawing.SolidBrush(c[cindex]);
                    Point dot = new Point(16, 16);
                    float angle = rand.Next(-RandAnlge, RandAnlge);//旋转度数
                    graph.TranslateTransform(dot.X, dot.Y);//移动光标到指定位置
                    graph.RotateTransform(angle);
                    graph.DrawString(chars[i].ToString(), f, b, 1, 1, format);
                    graph.RotateTransform(-angle);//转回去
                    graph.TranslateTransform(2, -dot.Y);//移动光标到指定位置
                }
                pbox.Image = map;
            }
            catch
            {
                MessageBox.Show("验证图片创建错误");
            }
        }
    }
}

更新验证码的方法

验证码验证失败及点击验证码需要更新,创建一个更新验证码的方法

private void UpdateVerificationCode()//Creat / update verification
{
    verificationCode = VerificationCode.CreateRandomCode(CodeLength);
    if (verificationCode == "") return;
    VerificationCode.CreateImage(verificationCode, picVCode);
}

验证验证码是否正确

获取用户输入的验证码判断是否正确

private bool CaptchaVerification()//Captcha verification
{
    if (String.IsNullOrEmpty(txbVCode.Text.Trim()) != true)
    {
        if (txbVCode.Text.Trim().ToLower() == verificationCode.ToLower()) return true;
        else
        {
            MessageBox.Show("验证码错误", "警告", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            UpdateVerificationCode();
            txbVCode.Text = "";
            txbVCode.Focus();
            return false;
        }
    }
    else
    {
        MessageBox.Show("请输入验证码", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
        UpdateVerificationCode();
        txbVCode.Text = "";
        txbVCode.Focus();
        return false;
    }
}

4.保存账号及密码功能的实现

在APP.config中先创建键值对用于储存复选框状态以及记录账号信息

<appSettings>
	<add key="remenberme" value=""/>
	<add key="loginID" value=""/>
	<add key="passwd" value=""/>
	<add key="roleID" value=""/>
</appSettings>

记录账号信息的函数

private void Remenberme()//Write user information
{
    string loginID = txbID.Text.Trim();
    string passwd = txbPwd.Text.Trim();
    Configuration cf = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
    if (chBRemenberMe.Checked)//Write
    {
        cf.AppSettings.Settings["loginID"].Value = loginID;
        cf.AppSettings.Settings["passwd"].Value = passwd;
        cf.AppSettings.Settings["remenberme"].Value = "true";
    }
    else//initialize
    {
        cf.AppSettings.Settings["loginID"].Value = "";
        cf.AppSettings.Settings["passwd"].Value = "";
        cf.AppSettings.Settings["remenberme"].Value = "false";
    }
    cf.Save();
}

在窗体加载的同时写入储存的登录信息

private void Login_Load(object sender, EventArgs e)//Read user information from App.config
{
    if (ConfigurationManager.AppSettings["remenberme"].Equals("true"))
    {
        txbID.Text = ConfigurationManager.AppSettings["loginID"];
        txbPwd.Text = ConfigurationManager.AppSettings["passwd"];
        chBRemenberMe.Checked = true;
    }
}

5.登录功能

进入系统功能

private void EnterSystem()
{
    DialogResult = DialogResult.OK;
    Remenberme();
}

点击按钮

private void btnLogin_Click(object sender, EventArgs e)//Determine whether to log in
{
    logonCount += 1;
    if (logonCount<=3)
    {
        if (loginFlag()) EnterSystem();
        else if (logonCount == 3) UpdateVerificationCode();
    }
    else if (CaptchaVerification()&&loginFlag()) EnterSystem();
}

四、登录页面完整代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using OlympicManagementSystem.Util;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Button;

namespace OlympicManagementSystem.Forms
{
    public partial class Login : Form
    {
        int roleID = 0;
        int logonCount = 0;
        private const int CodeLength = 4;
        private String verificationCode = "";

        public Login()
        {
            InitializeComponent();
        }

        private void btnLogin_Click(object sender, EventArgs e)//Determine whether to log in
        {
            logonCount += 1;
            if (logonCount<=3)
            {
                if (loginFlag()) EnterSystem();
                else if (logonCount == 3) UpdateVerificationCode();
            }
            else if (CaptchaVerification()&&loginFlag()) EnterSystem();
        }

        private void EnterSystem()
        {
            DialogResult = DialogResult.OK;
            Remenberme();
        }

        private void btnExit_Click(object sender, EventArgs e)//Exit System
        {
            System.Environment.Exit(0);
        }

        private void Login_Load(object sender, EventArgs e)//Read user information from App.config
        {
            if (ConfigurationManager.AppSettings["remenberme"].Equals("true"))
            {
                txbID.Text = ConfigurationManager.AppSettings["loginID"];
                txbPwd.Text = ConfigurationManager.AppSettings["passwd"];
                chBRemenberMe.Checked = true;
            }
        }

        private void UpdateVerificationCode()//Creat / update verification
        {
            verificationCode = VerificationCode.CreateRandomCode(CodeLength);
            if (verificationCode == "") return;
            VerificationCode.CreateImage(verificationCode, picVCode);
        }

        private bool CaptchaVerification()//Captcha verification
        {
            if (String.IsNullOrEmpty(txbVCode.Text.Trim()) != true)
            {
                if (txbVCode.Text.Trim().ToLower() == verificationCode.ToLower()) return true;
                else
                {
                    MessageBox.Show("验证码错误", "警告", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    UpdateVerificationCode();
                    txbVCode.Text = "";
                    txbVCode.Focus();
                    return false;
                }
            }
            else
            {
                MessageBox.Show("请输入验证码", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                UpdateVerificationCode();
                txbVCode.Text = "";
                txbVCode.Focus();
                return false;
            }
        }

        private void Remenberme()//Write user information
        {
            string loginID = txbID.Text.Trim();
            string passwd = txbPwd.Text.Trim();
            Configuration cf = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            if (chBRemenberMe.Checked)//Write
            {
                cf.AppSettings.Settings["loginID"].Value = loginID;
                cf.AppSettings.Settings["passwd"].Value = passwd;
                cf.AppSettings.Settings["remenberme"].Value = "true";
            }
            else//initialize
            {
                cf.AppSettings.Settings["loginID"].Value = "";
                cf.AppSettings.Settings["passwd"].Value = "";
                cf.AppSettings.Settings["remenberme"].Value = "false";
            }
            cf.Save();
        }

        private bool loginFlag()//Verify the user information,record roleID and return true or false
        {
            if (txbID.Text == "" || txbPwd.Text == "")
            {
                MessageBox.Show("用户名和密码不能为空", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return false;
            }
            else
            {//Query user information
                string sql = "select * from Staff where LoginID = '" + txbID.Text + "' and Password = '" + txbPwd.Text + "'";
                DataTable dataTable = SqlHelper.ExecuteTable(sql);
                if (dataTable.Rows.Count > 0)
                {
                    DataRow dataRow = dataTable.Rows[0];
                    roleID = (int)dataRow["RoleID"];
                    Configuration cf = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                    cf.AppSettings.Settings["roleID"].Value = roleID.ToString();//record roleID
                    cf.Save();
                    return true;
                }
                else
                {
                    MessageBox.Show("用户名或密码错误", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return false;
                }
            }
        }

        private void picVCode_Click(object sender, EventArgs e)//Click the image to update the verification code
        {
            if (logonCount>=3) UpdateVerificationCode();
        }
    }
}

五、运行效果

运行效果

后记

如果你这篇文章还不错的话,求点赞求收藏求转发,最重要的是你的支持是我做记录的最大动力,非常感谢!!!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值