企业项目开发--cookie(1)
此文已由作者赵计刚授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
注:本章代码基于《第五章 企业项目开发--mybatis注解与xml并用》的代码,链接如下:
http://www.cnblogs.com/java-zhao/p/5120792.html
在实际项目中,我们会存储用户状态信息,基本使用两种手段:cookie和session
1、cookie:
1.1、流程:
服务端将cookie的属性值设置好之后,通过HttpServletResponse将cookie写入响应头;
服务端从请求头中通过HttpServletRequest将所有cookie(当前被访问页面的所有cookie)读取出来,遍历寻找指定name的cookie即可。
流程与下边的例子对应一下,立刻就清楚了。
1.2、包含选项:(当前使用最多的就是version0版本的cookie,这里仅说version0的几个最常用的属性)
name:cookie名
value:cookie值
domain:cookie写在哪一个域下(例如:aaa.com)
path:cookie写在哪一个uri下(例如:/admin)
expires:cookie过期时间,超过某个指定时间点cookie就消失,当然设成-1的话,关闭浏览器cookie就会消失;指定了时间点的话,该cookie就会存在硬盘上
对于domain,一个例子解释清楚:
假设:www.baidu.com和e.baidu.com两个域,path="/",
1)当domain="baidu.com"时,两个域都可以访问生成的cookie
2)当domain="www.baidu.com"时,只有前一个域有生成cookie
对于path,用一个例子解释清楚:
假设http://www.baidu.com/dev/zz/和http://www.baidu.com/dev/xx/,
1)当path="/dev",生成的cookie上边的两个地址共享;
2)当path="/dev/zz",生成的cookie只有第一个地址有,第二个地址没有。
根据上边的例子,对于path与domain是相互依赖的,共同决定某个页面地址是否可以生成指定的cookie
1.3、优点:
基本不需要使用服务器空间,用户会话信息存在了客户端(这个只是列出来,基本不能算优点,反而应该算是缺点,因为存在客户端不安全)
在分布式系统中,因为cookie存在了浏览器,所以不需要考虑同一个用户怎样定位到同一台服务器这个问题
1.4、缺点:
cookie个数和总大小有限制,一般而言,每个域下可存放<=50个cookie,所有cookie的总大小<=4095个字节左右,chrome浏览器的cookie总大小会大很多(>80000个字节)。这些数据参考自《深入分析Java Web技术内幕》
如果cookie很多,客户端和服务端会浪费很对带宽,而且也会拖慢速度,一般而言,可以使用压缩算法做压缩,但是,可能压缩后的size也很大
不安全,如果被窃听者劫取到你的cookie,即使你对这些cookie做了加密,使其看不到cookie中的信息,但是其也可以通过该cookie模拟登录行为,然后获得一些权限,执行一些操作。(这是个疑问,记住我这个功能就是这样做的,怎样做到安全的呢?)(答案见最下方)
2、项目中使用cookie存储用户会话状态
代码实现:本章代码基于上一章代码实现,下面只列出修改或添加的一些类。
通常情况下,如果工具类很多,我们可以重开一个项目,例如:ssmm0-util,然后在这个子项目中添加类,当然,如果项目本身也不大,直接将工具类放在ssmm0-data子项目下即可。
2.1、ssmm0-data:
2.1.1、pom.xml:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4
5 <modelVersion>4.0.0</modelVersion>
6
7 <!-- 指定父模块 -->
8 <parent>
9 <groupId>com.xxx</groupId>
10 <artifactId>ssmm0</artifactId>
11 <version>1.0-SNAPSHOT</version>
12 </parent>
13
14 <groupId>com.xxx.ssmm0</groupId>
15 <artifactId>ssmm0-data</artifactId>
16
17 <name>ssmm0-data</name>
18 <packaging>jar</packaging><!-- 只是作为其他模块使用的工具 -->
19
20 <!-- 引入实际依赖 -->
21 <dependencies>
22 <!-- mysql -->
23 <dependency>
24 <groupId>mysql</groupId>
25 <artifactId>mysql-connector-java</artifactId>
26 </dependency>
27 <!-- 数据源 -->
28 <dependency>
29 <groupId>org.apache.tomcat</groupId>
30 <artifactId>tomcat-jdbc</artifactId>
31 </dependency>
32 <!-- mybatis -->
33 <dependency>
34 <groupId>org.mybatis</groupId>
35 <artifactId>mybatis</artifactId>
36 </dependency>
37 <dependency>
38 <groupId>org.mybatis</groupId>
39 <artifactId>mybatis-spring</artifactId>
40 </dependency>
41 <!-- servlet --><!-- 为了会用cookie -->
42 <dependency>
43 <groupId>javax.servlet</groupId>
44 <artifactId>javax.servlet-api</artifactId>
45 </dependency>
46 <!-- bc-加密 -->
47 <dependency>
48 <groupId>org.bouncycastle</groupId>
49 <artifactId>bcprov-jdk15on</artifactId>
50 </dependency>
51 <!-- cc加密 -->
52 <dependency>
53 <groupId>commons-codec</groupId>
54 <artifactId>commons-codec</artifactId>
55 </dependency>
56 </dependencies>
57 </project>
说明:
引入了servlet-jar包,主要是需要HttpServletResponse向响应头写cookie和使用HttpServletRequest从请求头读取cookie;
引入commons-codec和bouncy-castle,主要是为了实现AES加密与Base64编码。
注意:
servlet-jar的scope是provided,不具有传递性,所以如果在ssmm0-userManagement中需要用到servlet-jar,则ssmm0-userManagement需要自己再引一遍
commons-codec和bouncy-castle的scope都是采用了默认的compile,具有传递性,所以如果在ssmm0-userManagement中需要用到commons-codec和bouncy-castle,ssmm0-userManagement不需要自己再引一遍了
2.1.2、AESUtil:(AES加密)
1 package com.xxx.util;
2
3 import java.io.UnsupportedEncodingException;
4 import java.security.InvalidAlgorithmParameterException;
5 import java.security.InvalidKeyException;
6 import java.security.Key;
7 import java.security.NoSuchAlgorithmException;
8 import java.security.NoSuchProviderException;
9 import java.security.Security;
10 import java.security.spec.InvalidKeySpecException;
11
12 import javax.crypto.BadPaddingException;
13 import javax.crypto.Cipher;
14 import javax.crypto.IllegalBlockSizeException;
15 import javax.crypto.KeyGenerator;
16 import javax.crypto.NoSuchPaddingException;
17 import javax.crypto.SecretKey;
18 import javax.crypto.spec.SecretKeySpec;
19
20 import org.apache.commons.codec.binary.Base64;
21 import org.bouncycastle.jce.provider.BouncyCastleProvider;
22
23 /**
24 * 基于JDK或BC的AES算法,工作模式采用ECB
25 */
26 public class AESUtil {
27 private static final String ENCODING = "UTF-8";
28 private static final String KEY_ALGORITHM = "AES";//产生密钥的算法
29 private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";//加解密算法 格式:算法/工作模式/填充模式 注意:ECB不使用IV参数
30 private static final String ENCRYPT_KEY = "WAUISIgpBh1R/+3f2Ze4csUU/tl/O8x56DbVb7mTs7w=";//这个是先运行一遍getKey()方法产生的,然后卸载了这里。
31
32 /**
33 * 产生密钥(线下产生好,然后配在项目中)
34 */
35 public static byte[] getKey() throws NoSuchAlgorithmException{
36 Security.addProvider(new BouncyCastleProvider());//在BC中用,JDK下去除
37 KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
38 keyGenerator.init(256);//初始化密钥长度,128,192,256(选用192和256的时候需要配置无政策限制权限文件--JDK6)
39 SecretKey key =keyGenerator.generateKey();//产生密钥
40 return key.getEncoded();
41 }
42
43 /**
44 * 还原密钥:二进制字节数组转换为Java对象
45 */
46 public static Key toKey(byte[] keyByte){
47 Security.addProvider(new BouncyCastleProvider());//在BC中用,JDK下去除
48 return new SecretKeySpec(keyByte, KEY_ALGORITHM);
49 }
50
51 /**
52 * AES加密,并转为16进制字符串或Base64编码字符串
53 */
54 public static String encrypt(String data, byte[] keyByte) throws InvalidKeyException,
55 NoSuchAlgorithmException,
56 InvalidKeySpecException,
57 NoSuchPaddingException,
58 IllegalBlockSizeException,
59 BadPaddingException,
60 UnsupportedEncodingException,
61 NoSuchProviderException,
62 InvalidAlgorithmParameterException {
63 Key key = toKey(keyByte);//还原密钥
64 //Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);//JDK下用
65 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM,"BC");//BC下用
66 cipher.init(Cipher.ENCRYPT_MODE, key);//设置加密模式并且初始化key
67 byte[] encodedByte = cipher.doFinal(data.getBytes(ENCODING));
68 return Base64.encodeBase64String(encodedByte);//借助CC的Base64编码
69 }
70
71 /**
72 * AES解密
73 * @param data 待解密数据为字符串
74 * @param keyByte 密钥
75 */
76 public static String decrypt(String data, byte[] keyByte) throws InvalidKeyException,
77 NoSuchAlgorithmException,
78 InvalidKeySpecException,
79 NoSuchPaddingException,
80 IllegalBlockSizeException,
81 BadPaddingException,
82 UnsupportedEncodingException,
83 NoSuchProviderException,
84 InvalidAlgorithmParameterException {
85 Key key = toKey(keyByte);//还原密钥
86 //Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);//JDK下用
87 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM,"BC");//BC下用
88 cipher.init(Cipher.DECRYPT_MODE, key);
89 byte[] decryptByte = cipher.doFinal(Base64.decodeBase64(data));//注意data不可以直接采用data.getByte()方法转化为字节数组,否则会抛异常
90 return new String(decryptByte, ENCODING);//这里注意用new String()
91 }
92
93 /**
94 * 测试
95 */
96 public static void main(String[] args) throws NoSuchAlgorithmException,
97 InvalidKeyException,
98 InvalidKeySpecException,
99 NoSuchPaddingException,
100 IllegalBlockSizeException,
101 BadPaddingException,
102 UnsupportedEncodingException,
103 NoSuchProviderException,
104 InvalidAlgorithmParameterException {
105 String data = "找一个好姑娘做老婆是我的梦 想!";
106 /*************测试encryptAESHex()、decrypt()**************/
107 System.out.println("原文-->"+data);
108 byte[] keyByte3 = Base64.decodeBase64(ENCRYPT_KEY);
109 System.out.println("密钥-->"+Base64.encodeBase64String(keyByte3));//这里将二进制的密钥使用base64加密保存,这也是在实际中使用的方式
110 String encodedStr = AESUtil.encrypt(data, keyByte3);
111 System.out.println("加密后-->"+encodedStr);
112 System.out.println("解密String后-->"+AESUtil.decrypt(encodedStr, keyByte3));
113 }
114 }
说明:
关于AES的具体内容,可以参照"Java加密与解密系列的第八章",具体链接如下:
http://www.cnblogs.com/java-zhao/p/5087046.html
AESUtil这个类就是根据上边这篇博客的AESJDK这个类进行修改封装的。
注意:
AESUtil类的ENCRYPT_KEY变量的值是先运行了其中的getKey()方法,然后又通过Base64编码产生的,产生这个密钥后,我们将这个密钥写在类中。简单来说,就是线下先产生密钥,然后写在程序中,之后getKey()方法就再没有用了,可以直接删掉。
关于生成密钥的这段代码如下:
String key = Base64.encodeBase64String(AESUtil.getKey());
免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐
更多网易技术、产品、运营经验分享请点击。
相关文章:
【推荐】 css小点心
企业项目开发--cookie(1)的更多相关文章
- 第六章 企业项目开发--cookie
注:本章代码基于<第五章 企业项目开发--mybatis注解与xml并用>的代码,链接如下: http://www.cnblogs.com/java-zhao/p/5120792.html ...
- 企业项目开发--cookie(3)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 2.2.3.AdminController 1 package com.xxx.web.admin; ...
- 企业项目开发--cookie(2)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 2.1.3.CookieUtil:(cookie的基本操作:增删查,注意没有改) 1 package co ...
- 第八章 企业项目开发--分布式缓存memcached
注意:本节代码基于<第七章 企业项目开发--本地缓存guava cache> 1.本地缓存的问题 本地缓存速度一开始高于分布式缓存,但是随着其缓存数量的增加,所占内存越来越大,系统运行内存 ...
- 企业项目开发--分布式缓存memcached(3)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 3.3.ssmm0-data 结构: 3.3.1.pom.xml 1 <?xml version=& ...
- 第十一章 企业项目开发--消息队列activemq
注意:本章代码基于 第十章 企业项目开发--分布式缓存Redis(2) 代码的github地址:https://github.com/zhaojigang/ssmm0 消息队列是分布式系统中实现RPC ...
- 企业项目开发--分布式缓存Redis
第九章 企业项目开发--分布式缓存Redis(1) 注意:本章代码将会建立在上一章的代码基础上,上一章链接<第八章 企业项目开发--分布式缓存memcached> 1.为什么用Redis ...
- 第九章 企业项目开发--分布式缓存Redis(1)
注意:本章代码将会建立在上一章的代码基础上,上一章链接<第八章 企业项目开发--分布式缓存memcached> 1.为什么用Redis 1.1.为什么用分布式缓存(或者说本地缓存存在的问题 ...
- 第十章 企业项目开发--分布式缓存Redis(2)
注意:本章代码是在上一章的基础上进行添加修改,上一章链接<第九章 企业项目开发--分布式缓存Redis(1)> 上一章说了ShardedJedisPool的创建过程,以及redis五种数据 ...
随机推荐
- python正则表达式获取两段标记内的字符串
比如获取绿色字符串 ModelData.PayTableData =[{"}, {"}, {"}]; ModelData.PayTableData1 =[{"} ...
- 数据分析计算xgboost模块
一.安装xgboost方法 摘要:之前为了安装xgboost,少不了进入各种坑,但最终安装成功了!首先, 准备的工作:,下载mingw64,链接https://pan.baidu.com/s/1i5C ...
- 2018.11.02 洛谷P2312 解方程(数论)
传送门 直接做肯定会TLETLETLE. 于是考验乱搞能力的时候到了. 我们随便选几个质数来checkcheckcheck合法解,如果一个数无论怎么checkcheckcheck都是合法的那么就有很大 ...
- Apache和nginx 域名配置
apache配置 一.hosts配置: 1.用编辑器打开hosts文件,位置:C:\Windows\System32\drivers\etc目录下 2.在hosts文件里添加自己的域名配置,配置规则如 ...
- vue 开发系列(八) 动态表单开发
概要 动态表单指的是我们的表单不是通过vue 组件一个个编写的,我们的表单是根据后端生成的vue模板,在前端通过vue构建出来的.主要的思路是,在后端生成vue的模板,前端通过ajax的方式加载后端的 ...
- 深度优先搜索DFS和广度优先搜索BFS
DFS简介 深度优先搜索,一般会设置一个数组visited记录每个顶点的访问状态,初始状态图中所有顶点均未被访问,从某个未被访问过的顶点开始按照某个原则一直往深处访问,访问的过程中随时更新数组visi ...
- Go语言高级特性总结——Struct、Map与JSON之间的转化
Struct与Map之间互相转换 // Struct2Map convert struct to map func Struct2Map(st interface{}) map[string]inte ...
- 第02章:MongoDB安装
①下载 https://www.mongodb.com/ 下载所需版本的tar.gz ②解压安装 tar -zxvf mongodb-3.2.12.tar.gz mv -r mongodb-3.2. ...
- user\db\table_privs\column_privs四张表的权限控制
今天要做的测试是:user\db\table_privs\column_privs这四张权限表分别控制哪些级别的权限: 测试准备: [超级用户]root@'127.0.0.1' [操作库权限的用户]g ...
- Asp.net 修改已有数据的DataTable中某列的数据类型
DataTable dt_PI = new DataTable(); //克隆表结构 dt_PI = ds.Tables[].Clone(); dt_PI.Columns["FLTFullP ...