前两天为OA系统添加了登录日志,登录类型分三类:工业园IP登录、同步IP登录、短信验证码登录,写日志之前先判断用户账号是否存在是否允许登录继而是否是合法IP地址继而密码是否正确,如果是非工业园IP登录判断其短信验证码是否正确,以上验证都通过才写入日志记session, 测试正常即发布。上线后研究登录日志数据发现了奇怪的数据:类型为短信验证码登录但是并没有其他用户信息,而我在登录成功后都会记录登录账号、工号、时间、IP、登录结果等信息,断点调试代码也没有发现问题。遂在写日志的时候又加了层验证用户账号和密码如果不成功返回“Warning,非法登录请自行离去”,今早发布后终于有同事反馈OA无法登录并截图发给我,我发现他的登录账号含有大写字母而我们数据库中所有账号皆是小写,遂用该账号测试登录,果真发现问题根源……
先介绍下OA系统架构方面,我们使用MVC5+EF+Mysql,在底层封装了返回实体方法:
public IQueryable<T> LoadEntities(Func<T, bool> whereLambda) { return dbContext.Set<T>().Where<T>(whereLambda).AsQueryable(); }
问题就出在这个泛型委托参数whereLambda(不要问我为什么不用表达式查询,因为调用该方法的地方实在太多了……而且很多地方都用了类型转换), 而我新增的验证用户方法确实调用了该方法
hr_employee emp = emp_biz.LoadEntities(t => t.uid == model.UserID && t.pwd == pwd).FirstOrDefault();(注:pwd是经过加密的),当使用大写的账号登录时emp为null,而我在写日志之前的判断用户是否存在和密码是否正确时用的是直接linq查询hr_employee emp = dbContext.hr_employee.Where(t => t.uid == uid).FirstOrDefault(); 啰里啰嗦到写到现在相信大家都发现了问题根源,也一定知道为何如此,但是不是像我一样不大确定呢,那我们就用事实说话。我的猜想:问题就出在泛型委托上,它本身就是个方法,“==”对等条件就是两边必须一致才返回true,而单纯的linq where 查询就是sql语句。下面验证猜想。
1.Func<T,bool>
public ActionResult Index() { List<test23> list = new List<test23>(); list = LoadEntities(t =>t.name=="sean").ToList(); return View(list); } public IQueryable<test23> LoadEntities(Func<test23, bool> whereLambda) { OAEntities dbContext = new OAEntities(); return dbContext.Set<test23>().Where<test23>(whereLambda).AsQueryable(); }
前台输出:
2.linq查询
public ActionResult Index() { List<test23> list = new List<test23>(); using (OAEntities dbcontext = new OAEntities()) { list = dbcontext.test23.Where(t => t.name == "sean").ToList(); } //list = LoadEntities(t =>t.name=="sean").ToList(); return View(list); }
前台输出:
由此证明猜想。