发表于: 2017-11-17 23:01:50
1 708
一,继续任务
1;本来想着学完加密之后一块做,然后搞得有点乱,还是按部就班吧
设置session,然后设置对应的cookie(这里严格来说,并不是cookie而是sessionid,只是以cookie的形式发出去)然后添加到session,
测试,输入密码之后生成cookie键值对,
这个时候重新输入登陆路径不行,仍然要登陆,因为路径里没有假如判断语句;在登陆界面判断是否有缓存,跟踪到信息,有的话直接到home界面
再次测试ok,刷新登陆界面,直接传送到home界面
2;这个时候缓存机制已经用上了,该是拦截器了,也就是实现另一个功能;直接访问home界面不行,必须登陆才可以;然后是登陆过之后,也可以直接访问;
拦截器这个,感觉就是像aop的织入增强通知……action之前之后加入某些动作,也简单看一下
A;preHandle在业务处理器处理请求之前被调用
B;postHandle在业务处理器处理请求执行完成后,生成视图之前执行的动作
这里测试了一下,在方法里简单加入一个时间,看一下是否会解析到视图;
把拦截器的date放到jsp页面
测试正常显示,post果然是在controller之后,视图解析器之前…ok
C; afterCompletion在DispatcherServlet完全处理完请求后被调用,可用于清理资源等
D;代码框架大概就是这样,而要想实现上述的拦截功能,只需要套代码,把判断信息加上去;而且必须加到pre方法里面,这样在经过controller之前被拦截
然后是配置文件,简单看一下
到这里拦截功能已经实现了,遇到的一大串基础逻辑问题,写到下面了………
E;然后还是简单百度完整的总结一下拦截器的概念吧,以后也方便查看
(1)java拦截器
Java里的拦截器是动态拦截action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重用部分的方式。在AOP中拦截器用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。
Spring Web MVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。
(2)定义接口
SpringMVC 中的Interceptor 拦截请求是通过HandlerInterceptor 来实现的。在SpringMVC 中定义一个Interceptor 非常简单,主要有两种方式,第一种方式是要定义的Interceptor类要实现了Spring 的HandlerInterceptor 接口,或者是这个类继承实现了HandlerInterceptor 接口的类,比如Spring 已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter;第二种方式是实现Spring的WebRequestInterceptor接口,或者是继承实现了WebRequestInterceptor的类。
这里就第一种方式的两种方法做了简单的试了一下;效果一致
a; 定义的Interceptor类要实现了Spring 的HandlerInterceptor关键字implements
b; 定义的Interceptor类继承实现了HandlerInterceptor 接口的类,而Spring提供的实现接口的抽象类是HandlerInterceptorAdapter关键字extends
(3)实现接口方法
HandlerInterceptor 接口中定义了三个方法,我们就是通过这三个方法来对用户的请求进行拦截处理的。
preHandle:预处理回调方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器(如我们上一章的Controller实现);
返回值:true表示继续流程(如调用下一个拦截器或处理器);
false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;
postHandle:后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
afterCompletion:整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中preHandle返回true的拦截器的afterCompletion。
2;学习token知识概念
昨天学习了cookie和session,做了很多对比,实际上就功能机制而言没有什么大的区别,只能说通过Cookie,再更上一层次的设计上实现了为无状态的HTTP协议的Session机制。
而token;算是cookie验证后的产物,虽然不是cookie的一种,但是token可以以cookie的形式储存,传递的时候也可以用cookie的形式来传送,也可以写入url里传送,也就时所谓的URL重写技术。这里的话对于昨天的jsessionid就更清晰了,他们应该都算是sessionid,都是以cookie的形式状态来运行,但并不是cookie;另外Cookie通常是浏览器维护的,但是token不一定,可以以其他终端的形式维护。
然后是既然有了cookie以及session为什么又来一个token??昨天也看了,因为http协议的无状态所以需要cookie这种缓存跟踪技术;但是为了保存状态,每次都要验证信息,比较麻烦应该还算是浪费资源吧…假如服务器验证之后可以给用户一个有一定时限的token,那么用户就可以减少不必要的操作了;还有一方面就是涉及到安全的问题;cookie比较不安全,容易获取,而token名字听起来就比较安全……大概意思是跨站请求,http明文传送之类的……
还有就是token 的认证方式类似于临时的证书签名, 并且是一种服务器端无状态的认证方式,这就适合于 REST API 的场景. 因为这里的无状态就是服务端,不会保存身份认证相关的数据,而token 只被保存在客户端中的 cookie 或者相关的本地数据库localstorage;
也提一下缺点;简单来说, token一般都是 hash字符串什么鬼的,所以会增加额外的加密/解密的性能开销;还有就是即使加密方式同样也会存在安全隐患
然后是具体的token;令牌)由 uid+time+sign[+固定参数] 组成:
uid: 用户唯一身份标识
time: 当前时间的时间戳
sign: 签名, 使用 hash/encrypt 压缩成定长的十六进制字符串,以防止第三方恶意拼接
固定参数(可选): 将一些常用的固定参数加入到 token 中是为了避免重复查库
然后是流程,贴个图先....
1.用户登录校验,校验成功后就返回Token给客户端。
2.客户端收到数据后保存在客户端
3.客户端每次访问API是携带Token到服务器端。
4.服务器端采用filter过滤器校验。校验成功则返回请求数据,校验失败则返回错误码
找来工具类……根本看不懂……加盐……
3;接着完成的就是下面的一大串逻辑问题......
明日计划的事情:
1;完成加密内容...
2;完善任务...
3;提交任务...
遇到的问题及解决方法:
1;小问题也简单记录一下,设置好cookie之后,关闭浏览器重新登陆,仍然要输密码,嗯,忘了设置有效期限了….不设置的话,只是默认一次会话……嗯加上,就像下面那样…..
结果有效期还是零……想来想去不应该……就暂时搁置了……然后忘记了这个事……导致下面空指针的问题,下面具体说;
2.空指针异常,是写拦截器出现的,判断cookie的时候;
这是报错代码
这是判断条件1也是报错的地方1
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception
{
if (!check(request)) {
response.sendRedirect("/login");
}
System.out.println("preHandle(), 在访问Controller之前被调用");
return true;
}
这是判断的地方2,也是报空指针的地方2;
private boolean check(HttpServletRequest request) throws Exception
{
for (Cookie cookie : request.getCookies()) {
if (cookie.getName().equals("user")) {
if (cookie.getValue().equals(request.getSession().getAttribute("user"))) {
return true;
问题就是因为我第一个cookie时效问题,没解决导致cookie的生命周期是一次会话,这样遍历的时候就是,就是空…………然后方法返回到到上面的方法仍然是空…………
而我第一次改了cookie的时间失效的原因是,位置放错了…….
一开始没考虑这个细节…….放在add上面才有效
找到了问题所在;就好解决了,首先是改为正确的设置cookie的有效性;这样可以在浏览器端保存cookie;然后直接访问拦截的home路径,会去匹配;如果保存的有cookie那么就会直接登陆,如果没有匹配到就会返回true,然后跳到登陆界面;ok完成功能实现;
3;继续说上面的问题,看起来解决了问题,实现了功能,但是不够严谨,因为上面逻辑没有问题,有个前提就是在访问home之前必须要有cookie存在与浏览器客户端;如果把cookie清除,第一次不访问登陆界面,而直接访问home路径,那么之前写的判断还是会报空指针……
因为没有登陆之前是没有cookie存在的…遍历依然会报空指针…解决办法再加上判断条件,为空的时候也要跳出…
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("user")) {
if (cookie.getValue().equals(request.getSession().getAttribute("user"))) {
return true;
结论:出了问题,不要跳过……都是一个项目,不知不觉就影响到下一个步骤……另外就是,只靠自己逻辑还是不行,代码案例还是要多看,弥补逻辑业务考虑不全弊端
4;然后说紧接着的第四个问题………上面感觉所以的逻辑都完善了………理的也比较清了……我又闲的没事,清理关闭cookie试一下,再加上另一个判断,没有cookie的时候会不会正常跳到登陆界面,而不是报空指针……结果吓我一跳
又报了个500……
仔细一看确实不是空指针….是
大概意思是无法创建新的session,原因是服务器已经把信息响应给浏览器了,这样就无法创建sessionid了……….也就是response响应在创建session的之前了…
5,又没事测一下昨天的代码路径….发现又有问题了….特么又是空指针….
调试一下看看,又是少了判断语句……
加上解决….问题是昨天试了没问题的吧…….应该是我记错了……毕竟计算机比人脑好使….
再小结一下,以后关于传值的问题,一定要多思考,是否传过来,是否获取到….
6.关于equals这个判断,做了扩展,记得有可以不用写判断,同时规避空指针的方法,就是把可能为空的一侧写到equals右侧;也就是说比较的时候,假设cc与null比较,如果;
Null写到equals左边会报空指针;null.equals(cc)………会报空;
如果null写到右边cc.equals(null)是不会报空指针的,直接返回false;
按照这个思路,可以规避空指针,然后把上面root为null的部分写到右侧,这样就可以省去写if判断条件的繁杂部分,嗯,逻辑是看起来也没问题……
结果测试,还是报空指针;
把右侧换成null直接来测….
没问题…..这就奇了怪了…debug也只是说着一行有错,那么问题应该就是root了,root这个对象为空;那么当root是空,直接通过getuser的时候应该就报了空指针,并不是equals后跟了空才报的空……吧
虽然没有用这个方法规避空指针,不过整个流程还是学到了,解决问题的思路,以及debug简单的调试,还有思考问题的角度,花费的时间还可以接受
收获:
1;学习拦截器概念并使用
2;真正完善cookie以及session应用
3;进一步……认识了……空指针……
4;简单了解加密...
评论