前言
因为实习的时候遇到了公司cas
项目是我之前闻所未闻的。
因此写了一篇来记录学习cas
,但是发现得会很多计网知识。
所以从头到尾总结一下了,供大家参考学习!
对了我并不是写一个cas
项目,只是能看懂cas原理
就行。
参考文献
【狂神说Java】JavaWeb入门到实战_哔哩哔哩_bilibili
强烈推荐这篇文章,入门都能看懂个大概。
结合代码可以更好理解!
一文彻底搞清session、cookie、token的区别 - 知乎
Web
静态Web
动态Web
WebServer
Tomcat
成为目前比较流行的Web
应用服务器。
汤姆猫
Tomcat Downloads
Tomcat官网
:
Apache Tomcat® - Apache Tomcat 9 Software Downloads
Tomcat
需要注意的是需要有
Java
环境变量,配个Java
环境变量很简单的!
启动Tomcat
bin目录下的startup.bat
http://localhost:8080/
查看服务器核心配置文件
配置端口:
tomcat
默认端口:8080
http
:80
https
:443
#server.xml文件中
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
maxParameterCount="1000"
URIEncoding="UTF-8"
/>
配置主机的名称:
- 默认的主机名:
localhost
-> 127.0.0.1 - 默认网站应用存放的位置为:
webapps
域名解析:
#文件 这个文件不要随便修改
C:\Windows\System32\drivers\etc\hosts
127.0.0.1 www.xiaowang.com
#server.xml文件中
<Host name="www.xiaowang.com" appBase="webapps"
unpackWARs="true" autoDeploy="true">
点击startup.bat
http://www.xiaowang.com:8080/
网站是如何进行访问的?
输入一个域名:回车
HTTP
这章看个大概就行,用到查询对应的知识可能学的更快。我也只是简要介绍一下。
HTTP
(超文本传输协议)简单的请求-响应协议,它通常运行在TCP
之上。
Https
:安全的
Http
请求:
客户端 -> 发请求 -> 服务器
请求 URL:https://www.baidu.com/ //请求地址
请求方法:GET //post/get方法
状态代码:200 OK //状态码
远程地址:39.156.70.46:443
引用站点策略:strict-origin-when-cross-origin
accept:text/html //类型
accept-encoding:gzip, deflate, br, zstd //内容编码
accept-language:zh-CN,zh;q=0.9 //语言
cache-control:max-age=0 // 表示缓存的内容已经过期,必须重新请求。
connection:keep-alive // 连接:保持连接
请求行:
请求行中的请求方式:GET
请求方式:Get
,Post
Get
:请求能够携带的参数比较少,大小有限制,会在浏览器的URL
地址栏显示数据内容,不安全,但是高效!Post
:请求能够携带的参数没有限制,大小也没有限制,不会在浏览器的URL
地址栏显示数据内容,安全,但不高效。
消息头:
Accept:告诉浏览器,它所支持的数据类型
Accept-Encoding:支持哪种编码格式
Accept-Language:告诉浏览器,它的语言环境
Cache-Control:告诉浏览器,请求完成是端口还是保持连接
HOST:主机
Http
响应:
服务器 -> 响应 -> 客户端
connection:keep-alive //连接:保持连接
content-encoding:br //编码
content-type:text/html;charset=utf-8 //类型
响应体:
Accept:告诉浏览器,它所支持的数据类型
Accept-Encoding:支持哪种编码格式
Accept-Language:告诉浏览器,它的语言环境
Cache-Control:告诉浏览器,请求完成是端口还是保持连接
HOST:主机
Reflush:告诉客户端,多久刷新一次
Location:让网页重新定位
响应状态码:
200
:请求响应成功。
3xx
:请求重定向。
4xx
:找不到资源。
5xx
:服务器代码错误。502
网关错误。
Create Servlet
idea2022版创建Servlet文件(详细完整版)_idea怎么创建servlet文件-优快云博客
可能会出现问题:看下方链接解决!
[Tomcat 请求的资源/XXX/]不可用问题的解决方法_tomcat请求的资源不可用怎么解决-优快云博客
出现如下图就可!
http://localhost:8080/Servlet_war_exploded/servletTest
接下来按照我的目录改
非常重要务必跟着我改!!!!!!
idea配置了servlet后访问报错:java.lang.ClassNotFoundException: xxx.xxx.xxx.servlet.ServletDemo1 - 曹婷婷 - 博客园
做到这里能访问就是成功!
接下来我们写一个ServletTest
长大眼睛看好了这是service
方法后面都会用到!
我们的目的就是重写
HttpServlet
中的方法比如doGet
因为
HttpServlet
中写的并不是我们想要的!
//ServletTest文件
//get或者post只是请求实现的不同的方式可以互相调用,业务逻辑都一样。
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("进入doGet方法!");
//响应流 理解成输出吧!
PrintWriter writer = resp.getWriter();
writer.print("hello,Servlet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
为什么要写Servlet
的映射
写的是JAVA
程序,但是要通过浏览器访问,而浏览器需要连接web
服务器,所以需要在web
服务中注册写的Servlet
,还需要给他一个浏览器能够访问的路径;
//web.xml
//注册ServletTest
<servlet>
<servlet-name>Servlet</servlet-name>
<servlet-class>Servlet.ServletTest</servlet-class>
</servlet>
//Servlet的请求路径
<servlet-mapping>
<servlet-name>Servlet</servlet-name>
<url-pattern>/ServletTest</url-pattern>
</servlet-mapping>
/s1
是访问这个webapp
的index
(索引) /s1/ServletTest
再去请求那个servlet
(这里的就是ServletTest
)
Servlet
Servlet
是由Web
服务器调用,web
服务器在收到浏览器请求之后:
容器理解成服务器吧!
ServletContext
web
容器启动的时候,为每个web
程序创建一个对应的ServletContext
对象,它代表了当前的web
应用。
- 共享数据
在这个Servlet
中保存的数据,可以在另外一个Servlet
拿到。
//Servlet上下文
this.getServletContext();
- 修改
ServletTest
类,定义一个上下文对象ServletContext
,并且存储一个变量。
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//定义一个上下文对象
ServletContext servletContext = this.getServletContext();
//定义数据
String username = "小王";
//将一个数据保存在了ServletContext中名字为:username,值为:username
servletContext.setAttribute("username",username);
}
2.新增GetServlet
类,获取上下文中变量的值。
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//和在ServletTest 定义的servletContext是一个东西
ServletContext servletContext = this.getServletContext();
//获取键,程序不知道是啥因此需要强转一下
String username = (String) servletContext.getAttribute("username");
//防止乱码,如果想测试可以把这两行删除看看效果。
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
//打印
resp.getWriter().println("名字"+username);
}
3.修改web.xml
文件
<servlet>
<servlet-name>Servlet</servlet-name>
<servlet-class>Servlet.ServletTest</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet</servlet-name>
<url-pattern>/ServletTest</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>GetServlet</servlet-name>
<servlet-class>Servlet.GetServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GetServlet</servlet-name>
<url-pattern>/GetServlet</url-pattern>
</servlet-mapping>
Response sendRedirect
一个web
资源收到客户端请求后,会通知客户端去访问另外一个web
资源,这个过程叫做重定向。
常见场景:
- 用户登录
void sendRedirect(String var1) throws IOException;
Status Code状态码
:302跳转。
Location
:跳转路径。
//重定向就做了这两件事
resp.setHeader("Location","/hello");
resp.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
重定向和转发的区别
相同点:
- 页面都会实现跳转
不同点:
- 请求转发的时候,
url
不会变化。307
- 重定向的时候,
url
会发生变化。302
1.新增RequestTest
类
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("进入这个请求了");
req.getContextPath();
}
2.修改web.xml
文件
<servlet>
<servlet-name>RequestTest</servlet-name>
<servlet-class>Servlet.RequestTest</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RequestTest</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
3.修改index.jsp
文件
<%@ page contentType="text/html; charset=gb2312"%>
<html>
<head>
</head>
<body>
<h2>Hello World!</h2>
<%--这里提交的路径,需要寻找项目的路径--%>
<%-- ${pageContext.request.contextPath} 代表当前项目--%>
<form action="${pageContext.request.contextPath}/login" method="get">
用户名:<input type="text" name="username"> <br>
密码:<input type="password" name="password"> <br>
<input type="submit" value="提交">
</form>
</body>
</html>
处理请求:
1.再次修改RequestTest
文件
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username+":"+password);
//重定向时候一定要注意,路径问题,否则404
resp.sendRedirect("/s1/success.jsp");
}
2.写一个success.jsp
<%@ page contentType="text/html; charset=gb2312"%>
<html>
<head>
</head>
<body>
<h2>Success!</h2>
</form>
</body>
</html>
Request getRequestDispatcher
HttpServletRequest
代表客户端的请求,用户通过Http
协议访问服务器,HTTP
请求中的所有信息会被封装到HttpServletRequest
,通过这个HttpServletRequest
的方法,获得客户端的所有信息。
获取前端传送的参数、请求转发
1.创建LoginServlet
类
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8");
req.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
//获取多个数据(兴趣)
String[] hobbies = req.getParameterValues("hobbies");
System.out.println("=========================");
System.out.println(username);
System.out.println(password);
System.out.println(Arrays.toString(hobbies));
System.out.println("=========================");
//请求转发
// 这里的/代表当前web应用
//请求转发不需要项目名,转发是服务器内部跳转。
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
2.修改web.xml
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>Servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
3.编写index.jsp
和success.jsp
//index.jsp
<%@ page contentType="text/html; charset=gb2312"%>
<html>
<head>
<title>
登录
</title>
</head>
<body>
<h1>登录</h1>
<div style="text-align: center">
<%-- 这里表单表示的意思:以post方式提交表单,提交到我们的Login请求--%>
<form action="${pageContext.request.contextPath}/login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"> <br>
爱好:
<input type="checkbox" name="hobbies" value="女孩">女孩
<input type="checkbox" name="hobbies" value="代码">代码
<input type="checkbox" name="hobbies" value="唱歌">唱歌
<input type="checkbox" name="hobbies" value="电影">电影
<br>
<input type="submit">
</form>
</div>
</body>
</html>
//success.jsp
<%@ page contentType="text/html; charset=gb2312"%>
<html>
<head>
</head>
<body>
<h2>登 录 成 功!</h2>
</form>
</body>
</html>
Cookie
Cookie
就是饼干!很好理解的,就是你第一次访问我我会拦截你,然后我给你分一块饼干,当你有了这个饼干就相当于有了一个令牌,以后访问不会拦截你。
1.创建CookieServlet
类
//保存用户上一次访问的时间
public class CookieServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//服务器,告诉你,你来的时间,把这个时间封装成一个信件,你下次带来,就知道你来了。
//解决中文乱码
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
//打印
PrintWriter out = resp.getWriter();
//Cookie,服务器端从客户获取
Cookie[] cookies = req.getCookies();//这里返回数组,说明Cookie可能存在多个
//判断Cookie是否存在
if(cookies != null)
{
//如果存在怎么办?
out.write("last time is: ");
for(int i = 0;i < cookies.length;i++)
{
Cookie cookie = cookies[i];
//获取cookie的名字
if(cookie.getName().equals("lastLoginTime"))
{
//获取cookie中的值
Long lastLoginTime = Long.parseLong(cookie.getValue());
Date date = new Date(lastLoginTime);
out.write(date.toLocaleString());
}
}
}
else
{
out.write("这是您第一次访问本站!");
}
//服务器给客户端响应一个cookie;
Cookie cookie = new Cookie("lastLoginTime",System.currentTimeMillis()+"");
//cookie有效期为1天
cookie.setMaxAge(24*60*60);
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
2.修改web.xml
<servlet>
<servlet-name>CookieServlet</servlet-name>
<servlet-class>Servlet.CookieServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CookieServlet</servlet-name>
<url-pattern>/CookieServlet</url-pattern>
</servlet-mapping>
关于JSESSION留作伏笔
再次刷新就会出现时间。
那么时间是怎么拿到的呢?
响应头:
服务端传给客户端
请求头:
客户端把服务器给的cookie
返回服务器。
再关掉浏览器再访问网址
http://localhost:8080/s1/CookieServlet
就会发现时间没了因为session关闭了(浏览器关闭了)。
//cookie有效期为1天
cookie.setMaxAge(24*60*60);
Session
(重点)
- 服务器会给每一个用户(浏览器)创建一个
Session
对象。 - 一个
Session
独占一个浏览器,只要浏览器没有关闭,这个Session
就存在。 - 用户登录之后,整个网站它都可以访问!保存用户的信息,保存购物车的信息。
1.创建SessionServlet
类
public class SessionServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决乱码问题
resp.setCharacterEncoding("UTF-8");
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=utf-8");
//得到Session
HttpSession session = req.getSession();
//目前Session中存东西
session.setAttribute("name","小王");
//获取Session的ID
String sessionid = session.getId();
//判断Session是不是新创建
if(session.isNew())
{
resp.getWriter().write("session创建成功!ID:"+sessionid);
}
else
{
resp.getWriter().write("session已经再服务器中存在了,ID:"+sessionid);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
2.修改web.xml
<servlet>
<servlet-name>SessionServlet</servlet-name>
<servlet-class>Servlet.SessionServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SessionServlet</servlet-name>
<url-pattern>/SessionServlet</url-pattern>
</servlet-mapping>
Session
在浏览器一打开的时间就存在了!
Session
创建的时候做了啥?
Cookie cookie = new Cookie("JSESSIONID",sessionId);
resp.addCookie(cookie);
从Session
中取数据:
1.创建SessionServlet01
类
public class SessionServlet01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决乱码问题
resp.setCharacterEncoding("UTF-8");
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=utf-8");
//得到Session
HttpSession session = req.getSession();
String name = (String)session.getAttribute("name");
System.out.println(name);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
2.修改web.xml
<servlet>
<servlet-name>SessionServlet01</servlet-name>
<servlet-class>Servlet.SessionServlet01</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SessionServlet01</servlet-name>
<url-pattern>/SessionServlet01</url-pattern>
</servlet-mapping>
访问/SessionServlet01
-> 访问/SessionServlet
-> 访问/SessionServlet01
有数据
访问/SessionServlet01
访问/SessionServlet
以后再次 访问/SessionServlet01
有数据
总结一下
cookie
流程:
session
流程:
单点登录SSO
单点登录就是只登录一次,就能无缝的访问多个相关系统和应用。
每个单点登录的架构都需要实现一个CAS(Central Authentication Service)
服务
- 服务标识:每个系统或应用都会从
CAS
获得一个唯一标识 TGT Ticket
:成功通过CAS
认证后通过cookie
的形式发放给客户端的。比作游乐园门票,有了门票就可以玩游乐园里面的所有项目。Service Ticket(ST)
:好比是某个具体游玩项目的门票。通过TGT Ticket
门票领取具体某个游玩项目的门票ST
,才能玩那个项目。
当然这个过程不可能这么简单!简化版!
CAS
原理
CAS单点登录原理(包含详细流程,讲得很透彻,耐心看下去一定能看明白!)_java cas 登出逻辑-优快云博客
基本上我是参考该文章来理解的,没有任何抄袭的意思。只是加上我自己的拙见。
如果学会了上面的这些知识,下面这个简直是小cas
了!
第一次访问www.qiandu.com
标号1:用户访问http://www.qiandu.com,经过第一个过滤器(cas
提供,在web.xml
中配置)AuthenticationFilter
。(web.xml
都还记得把!)
主要作用:判断是否登录,如果没有登录则重定向到认证中心。
标号2:www.qiandu.com发现用户没有登录,则返回浏览器重定向地址。
首先可以看到我们请求www.qiandu.com,之后浏览器返回状态码302
(302重定向
对吧!之前说过的!)
让浏览器重定向到cas.qiandu.com
并且通过get
的方式添加参数service
,该参数目的是登录成功之后会要重定向回来,因此需要该参数。
其实server
的值就是编码之后请求www.qiandu.com的地址。
标号3:浏览器接收到重定向之后发起重定向,请求cas.qiandu.com
。
上图就是标号3
的请求,请求的URL
是标号2
返回的URL
。之后认证中心就展示登录的页面,等待用户输入用户名密码。
标号4:认证中心cas.qiandu.com
接收到登录请求,返回登陆页面。
标号5:用户在cas.qiandu.com
的login
页面输入用户名密码,提交。注意看from data
这个就是账号和密码。
标号6:服务器接收到用户名密码,则验证是否有效,验证逻辑可以使用cas-server
提供现成的,也可以自己实现。
上图就是标号5
的请求,以及标号6
的响应了。
cas.qiandu.com
即csa-server
认证通过之后,会返回给浏览器302
,重定向的地址就是Referer
中的service
参数对应的值。
后边并通过get
的方式挟带了一个ticket令牌
,这个ticket
就是ST
(数字3处
)。
同时会在Cookie
中设置一个CASTGC
,该cookie
是网站cas.qiandu.com
的cookie
,只有访问这个网站才会携带这个cookie
过去。
感觉是不是和sessionid
相似呢?
Cookie
中的CASTGC
:向cookie
中添加该值的目的是当下次访问cas.qiandu.com
时,浏览器将Cookie
中的TGC
携带到服务器,服务器根据这个TGC
,查找与之对应的TGT
。
从而判断用户是否登录过了,是否需要展示登录页面。TGT
与TGC
的关系就像SESSION
与Cookie
中SESSIONID
的关系。
TGT:Ticket Granted Ticket
(俗称大令牌,或者说票根,他可以签发ST)
TGC:Ticket Granted Cookie
(cookie
中的value
),存在Cookie
中,根据他可以找到TGT
。
ST:Service Ticket
(小令牌),是TGT
生成的,每个ST
只能使用一次,且有有效期限制。也就是上面数字3
处的ticket
值。
标号7
:浏览器从cas.qiandu.com
哪里拿到ticket
之后,就根据指示重定向到www.qiandu.com
,请求的url
就是上面返回的url
。
标号8:www.qiandu.com
在过滤器中会取到ticket
的值,然后通过http
方式调用cas.qiandu.com
验证该ticket
是否是有效的。
标号9:cas.qiandu.com
接收到ticket
之后,验证,验证通过返回结果告诉www.qiandu.com
该ticket
有效。
标号10:www.qiandu.com
接收到cas-server
的返回,知道了用户合法,展示相关资源到用户浏览器上。
总结
只是简要介绍了cas
原理、cookie
、Session
,工作应该是完全够用了。
如果要深入学习的话,还是得多敲代码!