cookie在浏览器是按照路径带出去的。
资料
代码
---01---
代码:
访问地址:http://localhost:8080/cookie_session_demo_Web_exploded/have-pencil.jsp
界面:
打开无痕窗口,这个是无缓存的:
COOKIE相当于身份证号,作为客户端的唯一标识。
SESSION相当于针对唯一标识,获取客户的状态。
IDEA如何导入eclipse的web项目:https://blog.csdn.net/zeal9s/article/details/90690524
servlet不存在:https://blog.csdn.net/qq_41283865/article/details/81865806
https://blog.csdn.net/wust_lh/article/details/73469789
这里直接是session了,session是自动的。
第一次访问的时候:
这个sessionId是当前的浏览器的唯一的身份认证,发送给服务器,服务器根据这个生成当前浏览器的session。seeionId只是存在浏览器的内存中。
再来:
cookie没有唯一的标识,服务器回自动给我们分配唯一标识,服务器,根据cookie取到session的。最开始是web容器给我们生成和管理的。
容器处理的是什么,就是根据cookie取出自己的session。
是web容器生成和管理的。
第一次访问的时候,生成cookie,返回给浏览器。
应用程序自己自动处理了,就是根据sessionId取出来了session。
完毕。
过程:第一次session.setAttribute返回一个cookie给浏览器。
cookie存的就是键值对
第二次根据cookie拿到session的铅笔,返回价格,自动拿cookie去找session了。
cookie是根据请求区分的,一个request一组cookie。
reponse.addCookie
request.getCookie
这些cookie在浏览器传播的,满足条件就带回来。
---
session
request.getSession(),通过cookie找到的session。
session.setAttribute
---
http://localhost:8080/cookie_session_demo_Web_exploded/have-pencil.jsp
在单点登陆我们如何设置呢?
我们访问百度就是百度的cookie:
下次我们访问新浪的话,不会把cookie发给新浪的。
什么是同一个cookie就是name secure domain path都是一样的。
删除:负数为删除
第一个域,第二个是路径,只有域和路径是一样的才会发送给服务器。
request是当前的请求。
package demo;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/path1/cookie-demo")
public class CookieDemoServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// cookie增删改查
// 读取cookie
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
System.out.println(cookie.getName() + ", "
+ cookie.getValue() + ", "
+ cookie.getMaxAge() + ", "
+ cookie.getPath() + ", "
+ cookie.getDomain() + ", "
+ cookie.getSecure() + ", "
+ cookie.isHttpOnly());
}
}
// 写cookie
Cookie cookie = new Cookie("mycookie", String.valueOf(System.currentTimeMillis())); // name & value
cookie.setHttpOnly(false); // JavaScript不能处理
cookie.setMaxAge(-1000); // expires:24小时过期
cookie.setSecure(false); // 如果为true,仅支持HTTPS协议
cookie.setPath("/path2");
// cookie.setDomain("www.test.loc");
response.addCookie(cookie);// 这句话返回给浏览器了在set-cookie消息头浏览期再次来的时候就会发送给服务器
// 删除cookie
// cookie.setMaxAge(-1); // expires:一个过去的时间
}
}
这个第一次访问是有session的cookie的,这个是web容器自动维护的。
访问:
http://localhost:8080/cookie_session_demo_Web_exploded/path1/cookie-demo
再次访问path1:
看下重点的东西,就是域名和路径。
当设置为根路径的时候。
---
jsp如何操作cookie?
内置对象:https://www.cnblogs.com/liuyangv/p/8059848.html
设置有效期,js操作是不是https是没有意义的。
escape是转码的意思,可以把中文什么的转为不含有歧义的。
document.cookie:https://www.cnblogs.com/PopularProdigal/p/7495226.html
代码:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>cookie demo</title>
</head>
<body>
<script type="text/javascript">
// cookie 增删改查 c1=test1; c2=new; c3=test3
var cookies = document.cookie;
console.log(cookies);
document.cookie="c3=test3";
document.cookie="c2=new";
// httpOnly 不允许js操作
docment.cookie="c4=test4;expires=" + [GMT时间] + ";path=/;domain=www.test.com;secure"
var d = new Date().getTime();
d += 24 * 60 * 60 * 1000;
document.cookie = "c1=test1;expires=" + new Date(d).toGMTString() ;
document.cookie = "c2=" + escape("内容转码防错误") + "";
// 去空格
function trim(str) {
return str.replace(/(^\s*)|(\s*$)/g, "");
}
// 获取cookie值 c1=test1; c2=%12%34%56%78%33%aba%20bc escape unescape
function getCookie(name) {
var cookies = document.cookie.split(";");
for (var i = 0, len = cookies.length; i < len; ++i) {
var cookie = cookies[i].split("=");
if (name === trim(cookie[0])) {
return unescape(trim(cookie[1]));// 对特殊字符转码
}
}
}
console.log(getCookie("c1"));
console.log(getCookie("c2"));
// 新增cookie(如果存在同名cookie,起到修改作用)
// expiresDay为有效天数
// domain提升到顶级域时,可使用.test.com形式
// 用js设置cookie,httpOnly属性浏览器支持情况不同,用js设置一般来说也没有意义
// c1=中文2;expires=3-6 2014GMT;path=/;domain=.test.com;secure
function addCookie(name, value, expiresDay, path, domain, isSecure) {
var tmp = name + "=" + escape(value);
if (expiresDay) {
var d = new Date().getTime();
d += expiresDay * 24 * 60 * 60 * 1000;
tmp += ";expires=" + new Date(d).toGMTString();
}
if (path) {
tmp += ";path=" + path;
}
if (domain) {
tmp += ";domain=" + domain;
}
if (isSecure) {
tmp += ";secure";
}
console.log(tmp);
document.cookie = tmp;
}
// 删除cookie,没有真正的删除,只能将cookie过期时间设置为过去时间,当浏览器关闭或重载页面时cookie被清除
function delCookie(name) {
document.cookie = name + "=anyval;expires=" + new Date(0).toGMTString();
}
delCookie("c1");
console.log(getCookie("c1"));
delCookie("new1");
delCookie("new2");
addCookie("new1", "新的一个");
addCookie("new2", "2new", null, "/path1", null, true);
</script>
</body>
</html>
---
问题:
---
cookie放在fliter里面。
拦截器:
session设置过其时间:https://blog.csdn.net/t2080305/article/details/81063737
---02---
认证中心:验证token生成token 登陆页面 注销接口。
客户端:拦截请求提取令牌交给认证中心,成功附加到请求,失败到认证中心的登陆页面。
转发和重定向:https://blog.csdn.net/weixin_40001125/article/details/88663468
灰白色是客户端,蓝色是认证中心,绿色是业务系统。
解读:
没有跨域的单点登陆:
单点登陆的服务端:
1.退出登陆,删除token与用户的关联 和 cookie。
2.没有登陆:get登陆请求过来,转发到单点登陆的服务器进行登陆(此时携带用户的地址,提交登陆信息将令牌和user关联加到内存,将令牌存到cookie),重定向到携带的用户地址再次走客户端的过滤器。
3.登陆了:带token发送http请求,验证token的有效性,通过cookie里面的令牌验证是否有对应的user,返回user没有返回null。
单点登陆的客户端(过滤器集成到用户),每次请求都要通过http请求去服务端验证:
1.从cookie中获取令牌,和当前路径。
2.http去服务端验证令牌不存在或者验证令牌是无效的,携带当前路径到服务端的登陆请求,转发到登陆页面。
3.验证通过,把用户加到request中,进入下次用户的下一个拦截器。
单点登陆的用户
1.集成客户端过滤器给自己
map的key就是token value就是user
cookie的name就是token value就是token
代码:
数据库的表:
---03---
重新访问:https://blog.csdn.net/qq_40910746/article/details/109618404
看下客户端首先访问:
同理app2
服务端模块的实现。
最后乱码是登陆成功跳转的界面。
首先看服务端的登陆授权功能:
我这个项目终于启动起来了:
第一步:
两个方法,一个是get一个是post
get就是到登录页面
post就是表单提交处理
package demo.sso.auth.controller;
import java.io.IOException;
import java.net.URLDecoder;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import demo.sso.TokenUserData;
import demo.sso.auth.service.UserAccountService;
import demo.sso.common.KeyGenerator;
import demo.sso.common.StringUtil;
import demo.sso.model.User;
/**
* user login
*/
@WebServlet("/login")
public class UserLoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
//private static String DOMAIN = ".test.loc";
private UserAccountService userAccountService = new UserAccountService();
/**
* 进入登录页
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 获得原始请求的url并保存传递,当登录成功时,让浏览器再次跳转到这个url
String origUrl = req.getParameter("origUrl");
req.setAttribute("origUrl", origUrl);
req.getRequestDispatcher("/WEB-INF/view/login.jsp").forward(req, resp);
}
/**
* 登录表单提交时处理
*/
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String account = request.getParameter("account");
String passwd = request.getParameter("passwd");
String origUrl = request.getParameter("origUrl");
// 按account查找用户
User user = null;
try {
user = userAccountService.findUserByAccount(account);
if (user != null) {
if (user.getPasswd().equals(passwd)) { // 判断密码是否正确
// 1 生成token
String token = KeyGenerator.generate();
// 2 将token user存储到全局唯一数据结构中
TokenUserData.addToken(token, user);
// 3 写cookie JVM
Cookie tokenCookie = new Cookie("token", token);
tokenCookie.setPath("/");
//tokenCookie.setDomain(DOMAIN);
tokenCookie.setHttpOnly(true);
response.addCookie(tokenCookie);
// 4 跳转到原请求
if (StringUtil.isEmpty(origUrl)) {
origUrl = "login_success";
} else {
// 跳转到请求的地址
origUrl = URLDecoder.decode(origUrl, "utf-8");
}
response.sendRedirect(origUrl);
} else {
backToLoginPage(request, response, account, origUrl,
"密码不正确");
}
} else { // 用户不存在
backToLoginPage(request, response, account, origUrl, "用户不存在");
}
} catch (SQLException e) {
e.printStackTrace();
backToLoginPage(request, response, account, origUrl, "发生系统错误!");
}
}
private void backToLoginPage(HttpServletRequest req,
HttpServletResponse resp, String account, String origUrl,
String errInfo) throws ServletException, IOException {
req.setAttribute("account", account);
req.setAttribute("origUrl", origUrl);
req.setAttribute("errInfo", errInfo);
req.getRequestDispatcher("/WEB-INF/view/login.jsp").forward(req, resp);
}
}
首先是get,则直接把跳转的地址存入reponse,转发到登录页面。
附加
存的全局的键值对的建是token 值是当前的user。把token放在cookie里面。
提交请求之后则:
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String account = request.getParameter("account");
String passwd = request.getParameter("passwd");
String origUrl = request.getParameter("origUrl");
// 按account查找用户
User user = null;
try {
user = userAccountService.findUserByAccount(account);
if (user != null) {
if (user.getPasswd().equals(passwd)) { // 判断密码是否正确
// 1 生成token
String token = KeyGenerator.generate();
// 2 将token user存储到全局唯一数据结构中
TokenUserData.addToken(token, user);
// 3 写cookie JVM
Cookie tokenCookie = new Cookie("token", token);
tokenCookie.setPath("/");
//tokenCookie.setDomain(DOMAIN);
tokenCookie.setHttpOnly(true);
response.addCookie(tokenCookie);
// 4 跳转到原请求
if (StringUtil.isEmpty(origUrl)) {
origUrl = "login_success";
} else {
origUrl = URLDecoder.decode(origUrl, "utf-8");
}
response.sendRedirect(origUrl);
} else {
backToLoginPage(request, response, account, origUrl,
"密码不正确");
}
} else { // 用户不存在
backToLoginPage(request, response, account, origUrl, "用户不存在");
}
} catch (SQLException e) {
e.printStackTrace();
backToLoginPage(request, response, account, origUrl, "发生系统错误!");
}
}
---
系统之间的通信方式:
关于web-inf路径:https://www.cnblogs.com/lbrs/p/12122325.html
注销:
什么是同一个cookie,一定要路径,domin都相同才可以的。
---04---
客户端模块的实现,客户端是整合到app里面的。:
代码:
package demo.sso.client;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import demo.sso.client.util.CookieUtil;
/**
* SSO客户端模块Filter
*
* @author Administrator
*
*/
public class SSOFilter implements Filter {
// SSO Server登录页面URL
private static final String SSO_LOGIN_URL = "/server/login",
SSO_VALIDATE_URL = "http://localhost:8080/server/validate";
// 拦截操作
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
// 从请求中提取token
String token = CookieUtil.getCookie(req, "token");
// 本次请求的完整路径 不包括?的
String origUrl = req.getRequestURL().toString();
String queryStr = req.getQueryString();
if (queryStr != null) {
origUrl += "?" + queryStr;
}
// token 不存在,跳转到SSOServer用户登录页 重定向
if (token == null) {
resp.sendRedirect(SSO_LOGIN_URL + "?origUrl="
+ URLEncoder.encode(origUrl, "utf-8"));
} else { // token存在,验证有效性
URL validateUrl = new URL(SSO_VALIDATE_URL + "?token=" + token);
HttpURLConnection conn = (HttpURLConnection) validateUrl
.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
byte[] buffer = new byte[is.available()];
is.read(buffer);
String ret = new String(buffer);
if (ret.length() == 0) { // 返回空字符串,表示 token无效
resp.sendRedirect(SSO_LOGIN_URL + "?origUrl="
+ URLEncoder.encode(origUrl, "utf-8"));
} else {
String[] tmp = ret.split(";");
User user = new User();
for (int i = 0; i < tmp.length; ++i) {
String[] attrs = tmp[i].split("=");
switch (attrs[0]) {
case "id":
user.setId(Integer.parseInt(attrs[1]));
break;
case "name":
user.setName(attrs[1]);
break;
case "account":
user.setAccount(attrs[1]);
break;
}
}
request.setAttribute("user", user);
chain.doFilter(request, response);
}
}
}
@Override
public void init(FilterConfig config) throws ServletException {
// do nothing
}
@Override
public void destroy() {
// do nothing
}
}
解读:request.getUrl得到的是什么呢:不包括问号和以后的部分的。
通过了 把user存在request里面
mvc配置过滤器:https://www.cnblogs.com/LiuOOP/p/11208830.html
生效其它的:https://blog.csdn.net/lero524/article/details/107832749
非maven项目打包jar:https://www.cnblogs.com/lianxuan1768/p/12752482.html
打包jar包:https://blog.csdn.net/qq_22136439/article/details/90692509
如何整合客户端呢?
是在app的filter配置的。
看下app2:
代码:
package app2;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import demo.sso.client.User;
public class PrivilegeFilter implements Filter {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 集成SSO前
// User loginUser = ((HttpServletRequest)request).getSession().getAttribute("loginUser");
// 从上一个Filter(SSOFilter)存入的属性中获取user,能执行到此处,一定是已登录
User user = (User) request.getAttribute("user");
// 可以根据user信息获得与本系统相关的用户业务信息
// Empl empl = EmplService.findEmplByUser(user.getId());
// 示范一个更详细的需要判定
String acc = user.getAccount();
if ("zs".equals(acc)) {
response.getWriter().write("zhangsan is forbidden!");
} else {
chain.doFilter(request, response);
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
---05---
浏览器的跨域安全限制:
jsonp举例:
当前在localhost域和127.0.0.1不是一个域。
---06---