Cookie
一、简介
- 某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密)。
- 通过 Cookie 和 Session 技术来实现记录访问者的一些基本信息 。
- Cookie 在计算机中是个存储在浏览器目录中的文本文件 。
二、特点
- 在同一个页面中设置 Cookie,实际上是按从后往前的顺序进行的。如果要先删除一个 Cookie,再写入一个 Cookie,则必须先写写入语句,再写删除语句,否则会出现错误 。
- Cookie是面向路径的。缺省路径 (path) 属性时,Web 服务器页会自动传递当前路径给浏览器,指定路径强制服务器使用设置的路径。在一个目录页面里设置的 Cookie 在另一个目录的页面里是看不到的 。
- Cookie 必须在 HTML 文件的内容输出之前设置;不同的浏览器 (Netscape Navigator、Internet Explorer) 对 Cookie 的处理不一致,使用时一定要考虑;客户端用户如果设置禁止 Cookie,则 Cookie 不能建立。 并且在客户端,一个浏览器能创建的 Cookie 数量最多为 300 个,并且每个不能超过 4KB,每个 Web 站点能设置的 Cookie 总数不能超过 20 个 。
三、源码
package javax.servlet.http;
import java.text.MessageFormat;
import java.util.ResourceBundle;
public class Cookie implements Cloneable {
private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");
private String name;
private String value;
private String comment;
private String domain;
private int maxAge = -1;
private String path;
private boolean secure;
private int version = 0;
private static final String tspecials = ",; ";
public Cookie(String name, String value) {
if (this.isToken(name) && !name.equalsIgnoreCase("Comment") && !name.equalsIgnoreCase("Discard") && !name.equalsIgnoreCase("Domain") && !name.equalsIgnoreCase("Expires") && !name.equalsIgnoreCase("Max-Age") && !name.equalsIgnoreCase("Path") && !name.equalsIgnoreCase("Secure") && !name.equalsIgnoreCase("Version") && !name.startsWith("$")) {
this.name = name;
this.value = value;
} else {
String errMsg = lStrings.getString("err.cookie_name_is_token");
Object[] errArgs = new Object[]{name};
errMsg = MessageFormat.format(errMsg, errArgs);
throw new IllegalArgumentException(errMsg);
}
}
public void setComment(String purpose) {
this.comment = purpose;
}
public String getComment() {
return this.comment;
}
public void setDomain(String pattern) {
this.domain = pattern.toLowerCase();
}
public String getDomain() {
return this.domain;
}
public void setMaxAge(int expiry) {
this.maxAge = expiry;
}
public int getMaxAge() {
return this.maxAge;
}
public void setPath(String uri) {
this.path = uri;
}
public String getPath() {
return this.path;
}
public void setSecure(boolean flag) {
this.secure = flag;
}
public boolean getSecure() {
return this.secure;
}
public String getName() {
return this.name;
}
public void setValue(String newValue) {
this.value = newValue;
}
public String getValue() {
return this.value;
}
public int getVersion() {
return this.version;
}
public void setVersion(int v) {
this.version = v;
}
private boolean isToken(String value) {
int len = value.length();
for(int i = 0; i < len; ++i) {
char c = value.charAt(i);
if (c < ' ' || c >= 127 || ",; ".indexOf(c) != -1) {
return false;
}
}
return true;
}
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException var2) {
throw new RuntimeException(var2.getMessage());
}
}
}
四、Cookie的使用
Cookie cookie = new Cookie("username","password"); // 新建Cookie
cookie.setMaxAge(Integer.MAX_VALUE); // 设置生命周期为MAX_VALUE
response.addCookie(cookie); // 输出到客户端
五、修改
只有添加方法,无修改方法,若要修改, 则只能再次生成一次,用后来的数据覆盖前面的数据(前提是key值必须相同)。
六、删除
也没有删除方法, 若要想实现删除Cookie的操作,那么我们需要将Cookie的maxAge
参数置为负数,比如说源码中的初始值就是-1,所以说我们也可以参考这个,如果要想将Cookie删除,我们也可以将其maxAge
参数置为-1。
七、有效期
maxAge
是Cookie的有效期,默认的情况下,Cookie的初始值是-1,其意思就是当浏览器退出时,清除Cookie。如果我们要想让Cookie保存一段时间,比如说是一周,其设置为72460*60(秒)。
八、注意:
修改、删除Cookie时,新建的Cookie除value、maxAge
之外的所有属性,例如name、path、domain等,都要与原Cookie完全一样。否则,浏览器将视为两个不同的Cookie不予覆盖,导致修改、删除失败。
九、域名
- Cookie是不可跨域名的。
- 正常情况下,同一个一级域名下的两个二级域名如
www.helloweenvsfei.com
和images.helloweenvsfei.com
也不能交互使用Cookie,因为二者的域名并不严格相同。如果想所有helloweenvsfei.com
名下的二级域名都可以使用该Cookie,需要设置Cookie的domain参数为“.helloweenvsfei.com
”。
十、校验
根据密码校验
根据Cookie中的用户名在数据库中查找,一旦找到该信息,立即将其取出,然后再与Cookie中的密码进行比较,如果一致,则验证通过。
/**
* 根据cookie中的密码进行校验
* @param request
* @param response
* @return
*/
@RequestMapping("/password")
public String password(HttpServletRequest request, HttpServletResponse response){
Cookie[] cookies = request.getCookies();
if(cookies.length > 0){
for(int i = 0;i < cookies.length;i ++){
Cookie cookie = cookies[i];
log.info("cookie的key为:{},value为:{}",cookie.getName(),cookie.getValue());
//验证登录信息
if(validParamPassword(cookie)){
return "success";
}
}
}
return "error";
}
/**
* 根据cookie中的密码进行校验
* @param cookie
* @return
*/
private Boolean validParamPassword(Cookie cookie){
if(cookie.getName().equals("zhangsan") && cookie.getValue().equals(MD5Util.encrypt("zhangsan123"))){
return true;
}
if(cookie.getName().equals("lisi") && cookie.getValue().equals(MD5Util.encrypt("lisi123"))){
return true;
}
return false;
}
根据最后一次Cookie时间进行校验
该方法的思路是每次服务器向用户颁发Cookie时都在数据库中更新一次Cookie颁发时间,这样如果下次访问,服务器可通过Cookie中的用户名在数据库中查出相应的信息,然后再与客户端的颁发时间进行比对,如果颁发时间一致,则验证通过,该方法的另一个优点是避免了用户密码存储在用户本地,因而更加的安全可靠。
/**
* 根据cookie中的存储时间进行校验
* @param request
* @param response
* @return
*/
@RequestMapping("/cookiedTime")
public String cookiedTime(HttpServletRequest request, HttpServletResponse response){
Cookie[] cookies = request.getCookies();
if(cookies.length > 0){
for(int i = 0;i < cookies.length;i ++){
Cookie cookie = cookies[i];
log.info("cookie的key为:{},value为:{}。",cookie.getName(),cookie.getValue());
//验证登录信息
if(validParamTime(cookie)){
return "success";
}
}
}
return "error";
}
/**
* 根据cookie存储时间进行校验
* @param cookie
* @return
*/
private Boolean validParamTime(Cookie cookie){
Test test = cookieService.selectByName(cookie.getName());
if(test != null){
if(String.valueOf(test.getUpdatetime().getTime()).equals(cookie.getValue())){
return true;
}
}
return false;
}