CurrentUser,也就是当前用户,这是我们系统中大量使用的一个概念。

确认当前用户

当然,我们利用的是cookie:用户的ID存放在cookie中,服务器端通过cookie中的Id,查找数据库,得到需要的用户信息。

那么,这里就有一个安全问题,如何防止cookie的伪造或篡改?我们采用了以下方法:

首先,cookie中除了存放用户Id,还存放了一个加密过后的验证码,其来源如下:

  • 未加密的验证码在用户生成时由系统随机产生,并存储在数据库中,如:287653;
  • 它会被使用MD5加密成我们看不懂的字符串,如:49b5f37dff119cf81fcb2b4e6077e17;

所以,当服务器端使用cookie中的用户Id时,会先检查加密过后的验证码是否有效。捏造的验证码是不会通过审核的。

还有一点需要说明的是,我们不考虑一个有效的cookie(连同验证码)被盗窃的情形。因为这就相当于你的电脑被别人使用了一样,我们确实无法判断使用你电脑的是不是你本人。

为什么没有使用session

可能有同学会想到,每次取cookie再查数据库,是不是会增加数据库负担,为什么不考虑session呢?两个方面的原因:

  • session有定时清理机制。不管时间长短,session总有可能被清理掉的时候,这个时候不能让用户再重新登录啊!多麻烦,是不是?你可以if(session["userInfo"]== null),再通过cookie取数据再装到session里,但何苦呢?
  • session难以同步更新,维护起来非常麻烦。比如当前用户发表一篇文章,积分增加了,你就得既改session又改数据库,这个同步过程是比较容易出问题的。
  • 上面两个问题,NHiernate的cache已经做得很好了,不会增加数据库负担,这个以后会讲。

CurrentUser的ViewModel

CurrentUser最麻烦的一件事情是:很多页面是根据不同的当前用户,显示不同的内容的。以“任务编辑”页面为例,当前用户是该任务的发布人,发布栏可编辑;否则,发布栏仅仅是可读的。

所以,最初我们的方案很简单,也封装一个CurrentUserModel就可以了呀!

但后来我们发现:

  • 需要判断的东西越来越多,比如还要判断当前用户是不是管理员、当前用户有没有验收权限、当前用户的上一次操作……把这些所有的信息都装到一个ViewModel里肯定是不合适的。怎么办呢?想到的自然就是拆分类,但CurrentUser还怎么拆分呢?
  • 页面的判断逻辑也变得复杂起来,比如当前用户有没有某种权限得查他的申请历史和批准情况,并且还得看当前文章是那种类型及其作者的权限等。这些大段大段的逻辑就写在View里面么?关键是有些数据是单个View取不到的,需要从其他地方(比如url parameter中)获取,这些都进一步的增加了复杂性。让我们不得不考虑,我们是不是应该把这些逻辑移到Controller中,然后直接将结果告诉View,保持View的干净清爽?

在MVC架构中,Controller将Model传递给View,其实可能有两种情况:

  1. View直接呈现Model的数据,比如直接显示CurrentUser的用户名
  2. View还可以利用Model中的数据进行运算,然后予以呈现,比如比较CurrentUser和当前任务的承接人

我曾经计划禁止掉第2种情形,也就是说:在View里面不需要任何计算,只负责呈现。用代码表示就是:

@if (Model.CurrentUserIsAccepter)
{
  //CurrentUserIsAccepter的值在controller中获取
}

而不是之前的:

@if (Model.CurrentUser.Id == Model.Accepter.Id)
{ }

但我们最终放弃了,因为实现起来太臃肿了。我们可以想象,这样的话,我们首先就至少需要三个Is属性:

    public class EditModel
{
public bool IsAccepter { get; set; }
public bool IsOwner { get; set; }
public bool IsPublisher { get; set; }
}

有点怪,但好像还可以接受,但后来情况发生了变化,我们还得考虑当前用户即是发布人又是承接人,或者即是承接人又是验收人,或者既是……又是……的情形:

    public class EditModel
{
public bool IsAccepter { get; set; }
public bool IsOwner { get; set; }
public bool IsPublisher { get; set; } public bool IsBothAccepterAndOwner { get; set; }
public bool IsBothAccepterAndPublisher { get; set; }
public bool IsBothPublisherAndOwner { get; set; }
//...... }

这代码给人的感觉就是有病了。关键是,谁知道以后还来不来一个“是…和…但不是……”的逻辑呢?到时候又该怎么办呢?

//任务编辑页面(/Task/Edit/{taskId})是一个页面呈现逻辑比较复杂的典型例子,我们前后大改了三次,才形成今天所使用的代码格局。
//我以前说我带的一个妹纸看着代码哭,哭的就是这里,呵呵
//有兴趣的同学可以研究一下。

所以,取巧是不行了,我们还是得面对这个问题:

如何划分Controller和View之间的逻辑/责任

更直白一点的讲,哪些事该Controller做,哪些事该View做?这个问题真的超级虐心。我想来想去,只能说:“能Controller做的,尽量让Controller做”。我自己对这个问题都相当不满意,但实在是没有办法啦。

具体到CurrentUser的ViewModel,我们提出以下两个原则:

  • 不包含需要和其他对象交互运算才能得到的数据,比如当前用户是不是当前任务的发布人,需要和“当前任务的发布人”做比较,就不能包含进来
  • 只能是需要多个View共用的数据,才能放进来。比如用户名,很多View都需要,就放进来好了。

为什么需要明确这些原则

可能你耐着性子看了上面的分析,最后却只得到一个似是而非又蛋疼的原则,会忍不住的问,“为什么一定需要/讲解这些原则?让程序员根据实际情况,自由发挥,不行么?”

浅层次的原因是要保证代码的可读性。阅读别人的代码是一件非常累的事情。但如果所有的代码都像一个人写的,而且这个人的思路自始至终都是非常清晰的,这样,我们会稍稍轻松一点。代码不是文学作品,在绝大多数情况下,不能天马行空自由发挥!

我们很多开发人员都已经开始注意代码的规范,但大多数还停留在缩进、换行、命名之类的细节(当然,这些也很重要)上;而架构师应站在一个更全局的高度,来“规范”所有的开发行为。

所以,其实更深层次的原因是:所有的代码都必须规范化。既然要规范化,那么首先就要有规范!先可以不管好坏,但至少要有。那么怎么制定完善这个规范呢?我分享一下我的经验:

  1. 按规范文档,做入职培训,培训可以着重讲道理,强化开发人员代码规范化的思维;
  2. 所有代码都必须review。review要往“挑刺”的方向靠,所以不规范的代码其实是很容易被发现的;
  3. 开发人员不服review的结果,review的人员要拿出依据(规范文档)来;
  4. 规范文档中如果还没有相关的规定,立即补充,并照此执行,包括改正以前不合规范的代码

这样不断的迭代,基本上就能不断的提高代码的规范性,并得到一份不错的规范文档。

好像写跑题了,又是项目管理方向的东西。就先这样吧!前台的架构,想想,剩下的应该就是单元测试(都还没做,所以暂时也讲不了),还有可能其他一些细节了,以后查漏补缺吧。接下来希望参与到项目的前台开发的同学就可以开始联系我了。博客系列我们将接着讲Service层。

架构之路(八)从CurrentUser说起的更多相关文章

  1. 架构之路(九)Session Per Request

    前面的两篇反应很差:没评论没赞.很伤心啊,为什么呢?搞得我好长一段时间都没更新了——呵呵,好吧,我承认,这只是我的借口.不过,还是希望大家多给反馈.没有反馈,我就只能猜了:前面两篇是不是写得太“粗”了 ...

  2. 第四章 电商云化,4.1 17.5W秒级交易峰值下的混合云弹性架构之路(作者:唐三 乐竹 锐晟 潇谦)

    4.1 17.5W秒级交易峰值下的混合云弹性架构之路 前言 每年的双11都是一个全球狂欢的节日,随着每年交易逐年创造奇迹的背后,按照传统的方式,我们的成本也在逐年上升.双11当天的秒级交易峰值平时的近 ...

  3. 架构之路:nginx与IIS服务器搭建集群实现负载均衡(二)

    [前言] 在<架构之路:nginx与IIS服务器搭建集群实现负载均衡(一)>中小编简单的讲解了Nginx的原理!俗话说:光说不练假把式.接下来,小编就和大家一起来做个小Demo来体会一下N ...

  4. 架构之路:nginx与IIS服务器搭建集群实现负载均衡(三)

    参考网址:https://blog.csdn.net/zhanghan18333611647/article/details/50811980 [前言] 在<架构之路:nginx与IIS服务器搭 ...

  5. .Net站点架构设计(八)測试

    .Net站点架构时间(八)測试 一般而言.总体測试策略是:先针对部分系统进行性能及压力測试,得到各部分的峰值处理性能:再模拟总体流程測试,此时倒不用依照峰值跑,重点測试总体业务流程及业务预期负荷. 在 ...

  6. [转帖]java架构之路-(面试篇)JVM虚拟机面试大全

    java架构之路-(面试篇)JVM虚拟机面试大全 https://www.cnblogs.com/cxiaocai/p/11634918.html   下文连接比较多啊,都是我过整理的博客,很多答案都 ...

  7. php架构之路

    鉴于最近跟小伙伴聊了很多PHP架构发展方向的问题,相关技术整理了一下,也顺便规划了一下自己的2019年. 一.常用的设计模式以及使用场景 以下是我用到过的   工厂,单例,策略,注册,适配,观察者,原 ...

  8. 架构之路:nginx与IIS服务器搭建集群实现负载均衡(一)

    最近亮亮在研究IIS的负载均衡!本人由于初出茅庐,防骗意识薄弱,一不小心被亮亮坑上了IIS负载均衡之路(亮亮是真黑哈!).前车之鉴啊!小伙伴们要小心.不过既上了贼船,便决定一条道走到黑.于是乎从大前天 ...

  9. Java之架构(0) - 架构之路

    软件架构作为一个概念,体现在技术和业务两个方面. 从技术角度来说:软件架构随着技术的革新不断地更新其内容,软件架构建立于当前技术和一些基本原则的基础之上. 先说一些基本原则: 分层原则:分层是为了降低 ...

随机推荐

  1. spring源码分析之context

    重点类: 1.ApplicationContext是核心接口,它为一个应用提供了环境配置.当应用在运行时ApplicationContext是只读的,但你可以在该接口的实现中来支持reload功能. ...

  2. 步入angularjs directive(指令)--点击按钮加入loading状态

    今天我终于鼓起勇气写自己的博客了,激动与害怕并存,希望大家能多多批评指导,如果能够帮助大家,也希望大家点个赞!! 用angularjs 工作也有段时间了,总体感觉最有挑战性的还是指令,因为没有指令的a ...

  3. c# Enumerable中Aggregate和Join的使用

    参考页面: http://www.yuanjiaocheng.net/ASPNET-CORE/asp.net-core-environment.html http://www.yuanjiaochen ...

  4. java8中lambda表达式的应用,以及一些泛型相关

    语法部分就不写了,我们直接抛出一个实际问题,看看java8的这些新特性究竟能给我们带来哪些便利 顺带用到一些泛型编程,一切都是为了简化代码 场景: 一个数据类,用于记录职工信息 public clas ...

  5. JDBC简介

    jdbc连接数据库的四个对象 DriverManager  驱动类   DriverManager.registerDriver(new com.mysql.jdbc.Driver());不建议使用 ...

  6. celery使用的一些小坑和技巧(非从无到有的过程)

    纯粹是记录一下自己在刚开始使用的时候遇到的一些坑,以及自己是怎样通过配合redis来解决问题的.文章分为三个部分,一是怎样跑起来,并且怎样监控相关的队列和任务:二是遇到的几个坑:三是给一些自己配合re ...

  7. FineBI:一个简单易用的自助BI工具

    过去,有关企业数据分析的重担都压在IT部门,传统BI分析更多面向的是具有IT背景的人员.但随着业务分析需求的增加,很多公司都希望为业务用户提供自助分析服务,将分析工作落实到业务人员手中.但同时,分析工 ...

  8. BPM配置故事之案例14-数据字典与数据联动

    小明遇到了点麻烦,他昨天又收到了行政主管发来的邮件,要求把出差申请单改由H3 BPM进行,表单如下 行政主管的出差申请表 小明对表单进行了调整,设计出了一份适合在系统中使用的表单,但在"出差 ...

  9. TabLayout + ViewPager

    一.实现思路 1.在build.gradle中添加依赖,例如: compile 'com.android.support:support-v4:23.4.0'compile 'com.android. ...

  10. Android中实现APP文本内容的分享发送与接收方法简述

    谨记(指定选择器Intent.createChooser()) 开始今天的内容前,先闲聊一下: (1)突然有一天头脑风暴,对很多问题有了新的看法和见解,迫不及待的想要分享给大家,文档已经写好了,我需要 ...