• 【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(5.1) 登录功能的实现,开始接触Spring IOC、DI


    索引

    【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目 目录索引

    简述

    今天我们做登录,今天的东西比较多,用到了Spring的IOC和DI、接口的使用、验证等,希望大家多多讨论

    项目准备

    我们用的工具是:VS 2013 + SqlServer 2012 + IIS7.5

    希望大家对ASP.NET MVC有一个初步的理解,理论性的东西我们不做过多解释,有些地方不理解也没关系,会用就行了,用的多了,用的久了,自然就理解了。

    项目开始

    一、首先简单介绍一下IOC和DI

    Ioc:Inversion of Control,即“控制反转”,他不是什么新的技术,而是一种设计思想。

    通常我们是这么理解,我们一般的设计思想是在对象内部直接控制,而IOC是将设计好的对象交给容器控制,而不是传统的在对象内部直接控制。

    打个比方:我们租房子,在我们和房主之间插入了一个中间人(房介),我们只需要跟房介提出我们的要求,比如房子要三室一厅、卧室向阳、房东是女的(*^_^* )、楼层不要太低、遮光不要太长等等等等,然后房介就会按照我们的要求给我们提供一个房产信息,我们满意就跟租赁、入住,如果我们不满意(抛出异常),房介就会帮我们做后续处理。整个过程不再是由我们控制,而是由房介这么一个容器去控制。所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。

    DI:IOC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。那么DI是如何实现的呢? 有一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。

    如果你还不理解,那么请移步百度~~

    二、理论性的东西,通过代码的实现更容易理解一些,现在我们来做用户管理的接口

    我们首先在Service类库下面创建两个文件夹 IService(存放接口)、ServiceImp(实现类),并且在这两个文件夹下面再分别建两个文件夹ComManage和SysManage,用户区分管理我们的接口和实现类

    我们创建系统管理用户SYS_USER的接口:右击IService/SysManage→添加→新建项→接口  我们叫做IUserManage

    SysManage只是我们为了区分管理我们的接口文件,我们修改一下命名空间,让他们统一在Service.IService空间下,并且我们继承基础数据操作接口 IRepository

    我们添加接口方法:验证登录、判断是否为管理员、根据用户ID获取用户名

    代码:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Service.IService
     8 {
     9     /// <summary>
    10     /// Service层基本用户信息接口
    11     /// add yuangang by 2016-05-12
    12     /// </summary>
    13     public interface IUserManage:IRepository<Domain.SYS_USER>
    14     {
    15        /// <summary>
    16         /// 管理用户登录验证,并返回用户信息与权限集合
    17        /// </summary>
    18        /// <param name="username">用户账号</param>
    19        /// <param name="password">用户密码</param>
    20        /// <returns></returns>
    21         Domain.SYS_USER UserLogin(string useraccount, string password);
    22        /// <summary>
    23         /// 是否超级管理员
    24        /// </summary>
    25        /// <param name="userId">用户ID</param>
    26        /// <returns></returns>
    27         bool IsAdmin(int userId);
    28         /// <summary>
    29         /// 根据用户ID获取用户名,不存在返回空
    30         /// </summary>
    31         /// <param name="userId">用户ID</param>
    32         /// <returns></returns>
    33         string GetUserName(int userId);
    34     }
    35 }
    View Code

     我们创建用户接口的实现类:右击ServiceImp/SysManage→添加→类→  我们叫做UserManage

    同样,我们修改一下命名空间,让他们统一在Service.ServiceImp空间下,并且我们继承基础数据操作类 RepositoryBase和他的接口IUserManage

    我们分别实现接口的方法:

    代码:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Service.ServiceImp
     8 {
     9     public class UserManage:RepositoryBase<Domain.SYS_USER>,IService.IUserManage
    10     {
    11         /// <summary>
    12         /// 管理用户登录验证
    13         /// add yuangang by 2016-05-12
    14         /// </summary>
    15         /// <param name="useraccount">用户名</param>
    16         /// <param name="password">加密密码(AES)</param>
    17         /// <returns></returns>
    18         public Domain.SYS_USER UserLogin(string useraccount, string password)
    19         {
    20             var entity = this.Get(p => p.ACCOUNT == useraccount);
    21             
    22             //因为我们用的是AES的动态加密算法,也就是没有统一的密钥,那么两次同样字符串的加密结果是不一样的,所以这里要通过解密来匹配
    23             //而不能通过再次加密输入的密码来匹配
    24             if (entity != null && new Common.CryptHelper.AESCrypt().Decrypt(entity.PASSWORD) == password)
    25             {
    26                 return entity;
    27             }
    28             return null;
    29         }
    30 
    31         /// <summary>
    32         /// 是否超级管理员
    33         /// </summary>
    34         public bool IsAdmin(int userId)
    35         {      
    36             //这里我们还没有做用户角色 所以先返回个True,后面我们做角色的时候再回来修改
    37             return true;
    38         }
    39 
    40         /// <summary>
    41         /// 根据用户ID获取用户名
    42         /// </summary>
    43         /// <param name="Id">用户ID</param>
    44         /// <returns></returns>
    45         public string GetUserName(int Id)
    46         {
    47             var query = this.LoadAll(c => c.ID == Id);
    48             if (query == null || !query.Any())
    49             {
    50                 return "";
    51             }
    52             return query.First().NAME;
    53         }
    54     }
    55 }
    View Code

    重要:在这说明一下,因为之前我一直用的DES加密算法,后来改成了AES动态加密,但是Common类库下面的CryptHelper/DESCrypt一直没有改过来,这给很多细心的朋友造成了困扰,命名方法体就是 【C#公共帮助类】给大家分享一些加密算法 (DES、HashCode、RSA、AES等) 里的AES,这里怎么是DES呢?首先,我表示抱歉,在这呢,一劳永逸,我修改了Common/CryptHelper/DESCrypt,目前我们用到的地方只有两个,一个就是我们上面代码中的 UserLogin,另一个是Common/Utils.cs 第1611行, 获得当前完整Url地址。大家修改一下。

     

    我重新把修改后的代码贴一下:

      1 using System;
      2 using System.Collections.Generic;
      3 using System.IO;
      4 using System.Linq;
      5 using System.Security.Cryptography;
      6 using System.Text;
      7 
      8 namespace Common.CryptHelper
      9 {
     10     public class AESCrypt
     11     {
     12        public const string RET_ERROR = "x07x07x07x07x07";
     13        private byte[] _IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
     14        private byte[] _Key = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
     15        private const string CRYPTO_KEY = "WKMVCYUANGANG";
     16        private int CRYPTO_KEY_LENGTH = 32;
     17   
     18        private AesCryptoServiceProvider m_aesCryptoServiceProvider;
     19        private string m_message;
     20        public string Message
     21        {
     22            get { return m_message; }
     23            set { m_message = value; }
     24        }
     25        private bool m_containKey;
     26        /// <summary>
     27        /// True:密文中包含密钥
     28        /// False:密文中不包含密钥
     29        /// </summary>
     30        public bool ContainKey
     31        {
     32            get { return m_containKey; }
     33            set { m_containKey = value; }
     34        }
     35        public AESCrypt()
     36        {
     37            m_aesCryptoServiceProvider = new AesCryptoServiceProvider();
     38            m_containKey = true;
     39            m_message = string.Empty;
     40        }
     41        public AESCrypt(bool containKey)
     42            : this()
     43        {
     44            m_containKey = containKey;
     45        }
     46        private string Encrypt(string s_crypto, byte[] key)
     47        {
     48            string s_encryped = string.Empty;
     49            byte[] crypto, encrypted;
     50            ICryptoTransform ct;
     51   
     52            try
     53            {
     54                crypto = string2Byte(s_crypto);
     55                m_aesCryptoServiceProvider.Key = key;
     56                m_aesCryptoServiceProvider.IV = _IV;
     57                ct = m_aesCryptoServiceProvider.CreateEncryptor();
     58                encrypted = ct.TransformFinalBlock(crypto, 0, crypto.Length);
     59                if (m_containKey)
     60                {
     61                    s_encryped += byte2HexString(key);
     62                }
     63                s_encryped += byte2HexString(encrypted);
     64                return s_encryped;
     65            }
     66            catch (Exception ex)
     67            {
     68                m_message = ex.ToString();
     69                return RET_ERROR;
     70            }
     71        }
     72        /// <summary>
     73        /// 指定密钥对明文进行AES加密
     74        /// </summary>
     75        /// <param name="s_crypto">明文</param>
     76        /// <param name="s_key">加密密钥</param>
     77        /// <returns></returns>
     78        public string Encrypt(string s_crypto, string s_key)
     79        {
     80            byte[] key = new byte[CRYPTO_KEY_LENGTH];
     81   
     82            byte[] temp = string2Byte(s_key);
     83            if (temp.Length > key.Length)
     84            {
     85                m_message = "Key too long,need less than 32 Bytes key.";
     86                return RET_ERROR;
     87            }
     88            key = string2Byte(s_key.PadRight(key.Length));
     89            return Encrypt(s_crypto, key);
     90        }
     91        /// <summary>
     92        /// 动态生成密钥,并对明文进行AES加密
     93        /// </summary>
     94        /// <param name="s_crypto">明文</param>
     95        /// <returns></returns>
     96        public string Encrypt(string s_crypto)
     97        {
     98            byte[] key = new byte[CRYPTO_KEY_LENGTH];
     99   
    100            m_aesCryptoServiceProvider.GenerateKey();
    101            key = m_aesCryptoServiceProvider.Key;
    102            return Encrypt(s_crypto, key);
    103        }
    104   
    105        private string Decrypt(string s_encrypted, byte[] key)
    106        {
    107            string s_decrypted = string.Empty;
    108            byte[] encrypted, decrypted;
    109            ICryptoTransform ct;
    110   
    111            try
    112            {
    113                encrypted = hexString2Byte(s_encrypted);
    114                m_aesCryptoServiceProvider.Key = key;
    115                m_aesCryptoServiceProvider.IV = _IV;
    116                ct = m_aesCryptoServiceProvider.CreateDecryptor();
    117                decrypted = ct.TransformFinalBlock(encrypted, 0, encrypted.Length);
    118                s_decrypted += byte2String(decrypted);
    119                return s_decrypted;
    120            }
    121            catch (Exception ex)
    122            {
    123                m_message = ex.ToString();
    124                m_message = "Decrypt fail.";
    125                return RET_ERROR;
    126            }
    127        }
    128        /// <summary>
    129        /// 从密文中解析出密钥,并对密文进行解密
    130        /// </summary>
    131        /// <param name="s_encrypted">密文</param>
    132        /// <returns></returns>
    133        public string Decrypt(string s_encrypted)
    134        {
    135            string s_key = string.Empty;
    136            byte[] key = new byte[CRYPTO_KEY_LENGTH];
    137   
    138            if (s_encrypted.Length <= CRYPTO_KEY_LENGTH * 2)
    139            {
    140                m_message = "Encrypted string invalid.";
    141                return RET_ERROR;
    142            }
    143            if (m_containKey)
    144            {
    145                s_key = s_encrypted.Substring(0, CRYPTO_KEY_LENGTH * 2);
    146                s_encrypted = s_encrypted.Substring(CRYPTO_KEY_LENGTH * 2);
    147            }
    148            key = hexString2Byte(s_key);
    149            return Decrypt(s_encrypted, key);
    150        }
    151        /// <summary>
    152        /// 指定密钥,并对密文进行解密
    153        /// </summary>
    154        /// <param name="s_encrypted">密文</param>
    155        /// <param name="s_key">密钥</param>
    156        /// <returns></returns>
    157        public string Decrypt(string s_encrypted, string s_key)
    158        {
    159            byte[] key = new byte[CRYPTO_KEY_LENGTH];
    160   
    161            byte[] temp = string2Byte(s_key);
    162            if (temp.Length > key.Length)
    163            {
    164                m_message = "Key invalid.too long,need less than 32 Bytes";
    165                return RET_ERROR;
    166            }
    167            key = string2Byte(s_key.PadRight(key.Length));
    168            if (m_containKey)
    169            {
    170                s_encrypted = s_encrypted.Substring(CRYPTO_KEY_LENGTH * 2);
    171            }
    172            return Decrypt(s_encrypted, key);
    173        }
    174 
    175        #region 私有方法
    176        private string byte2HexString(byte[] bytes)
    177        {
    178            StringBuilder sb = new StringBuilder();
    179            foreach (byte b in bytes)
    180            {
    181                sb.AppendFormat("{0:X2}", b);
    182            }
    183            return sb.ToString();
    184        }
    185        private byte[] hexString2Byte(string hex)
    186        {
    187            int len = hex.Length / 2;
    188            byte[] bytes = new byte[len];
    189            for (int i = 0; i < len; i++)
    190            {
    191                bytes[i] = (byte)(Convert.ToInt32(hex.Substring(i * 2, 2), 16));
    192            }
    193            return bytes;
    194        }
    195        private byte[] string2Byte(string str)
    196        {
    197            return Encoding.UTF8.GetBytes(str);
    198        }
    199        private string byte2String(byte[] bytes)
    200        {
    201            return Encoding.UTF8.GetString(bytes);
    202        }
    203        #endregion
    204 
    205     
    206     }
    207 }
    View Code

     这是一个小小的插曲~~~

     

    我们继续,我们在Service类库下面新建一个文件夹Config用于存放注入文件,我们在这个文件夹下面新建两个XML文件ComService.xml和Service.xml

    我们把这两个文件属性的生成操作修改为嵌入的资源:分别右击这两个XML文件→属性→生成操作→嵌入的资源

    然后我们移步操作WebPage,我们新建个文件夹Config,然后新建3个XML文件:

    ComControllers.xml:后台管理Com控制器

    Controllers.xml:后台管理Sys控制器

    IndexControllers.xml:网站前台控制器

    分别更改3个文件属性的生成操作修改为嵌入的资源(同上)

     

    下一步我们修改一下WebPage的 Web.Config 声明一下Spring容器和配置指向,注意他们的位置

    代码:

    Spring声明容器

    1 <sectionGroup name="spring">
    2       <!--Spring声明容器-->
    3       <section name="context" type="Spring.Context.Support.MvcContextHandler, Spring.Web.Mvc5" />
    4       <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
    5     </sectionGroup>
    View Code

    Spring配置指向

     1 <!--Spring配置指向-->
     2   <spring>
     3     <context>
     4       <!--WebPage-->
     5       <resource uri="assembly://WebPage/WebPage.Config/IndexControllers.xml" />
     6       <resource uri="assembly://WebPage/WebPage.Config/Controllers.xml" />
     7       <resource uri="assembly://WebPage/WebPage.Config/ComControllers.xml" />
     8       <!--Service-->
     9       <resource uri="assembly://Service/Service.Config/Service.xml" />
    10       <resource uri="assembly://Service/Service.Config/ComService.xml" />
    11     </context>
    12   </spring>
    View Code

    由于大家是比较着急的,时间呢又是那么的不经用,所以这一篇文章,我们分为几部分来写,今天的第一部分,我们先到这,下一部分,我会抓紧写~~~

    原创文章 转载请尊重劳动成果 http://yuangang.cnblogs.com

  • 相关阅读:
    Leetcode单链表反转
    算法--二叉搜索树的python实现
    云服务器(阿里和腾讯)搭建网络云盘Nextcloud
    VGG16和集成模型(LeNet,CNN,Net均匀池化)比较
    git与github
    pyspider-崔庆才猫途鹰
    给 Python 添加进度条 | 给小白的 tqdm 精炼实例!
    @wraps 修饰器:让你的 Python 代码更加简短可爱 | 从简单实例来认识它
    并发和并行 | Python中实现多线程 threading 和多进程 multiprocessing
    Python格式化字符串字面值 | 被官方文档称之为『漂亮』的输出格式
  • 原文地址:https://www.cnblogs.com/yuangang/p/5484455.html
Copyright © 2020-2023  润新知