CAS逻辑

前言

因为实习的时候遇到了公司cas项目是我之前闻所未闻的。

因此写了一篇来记录学习cas,但是发现得会很多计网知识。

所以从头到尾总结一下了,供大家参考学习!

对了我并不是写一个cas项目,只是能看懂cas原理就行。

项目地址

参考文献

【狂神说Java】JavaWeb入门到实战_哔哩哔哩_bilibili

强烈推荐这篇文章,入门都能看懂个大概。

结合代码可以更好理解!

一文彻底搞清session、cookie、token的区别 - 知乎

Web

静态Web

image-20250221143807804

动态Web

image-20250221145027346

WebServer

Tomcat

成为目前比较流行的Web应用服务器。

汤姆猫

Tomcat Downloads

Tomcat官网

Apache Tomcat® - Apache Tomcat 9 Software Downloads

image-20250217212905050

image-20250220224313641

Tomcat

需要注意的是需要有Java环境变量,配个Java环境变量很简单的!

image-20250221150745398

启动Tomcat

bin目录下的startup.bat
http://localhost:8080/

查看服务器核心配置文件

image-20250221151229868

配置端口

  • tomcat默认端口:8080
  • http80
  • https443
#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/

image-20250221152414878

网站是如何进行访问的?

输入一个域名:回车

image-20250221154257389

HTTP

这章看个大概就行,用到查询对应的知识可能学的更快。我也只是简要介绍一下。

HTTP(超文本传输协议)简单的请求-响应协议,它通常运行在TCP之上。

Https:安全的

Http请求

客户端 -> 发请求 -> 服务器

image-20250221155721431

请求 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

请求方式:GetPost

  • 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文件-优快云博客

image-20250220114318520

可能会出现问题:看下方链接解决!

[Tomcat 请求的资源/XXX/]不可用问题的解决方法_tomcat请求的资源不可用怎么解决-优快云博客

出现如下图就可!

http://localhost:8080/Servlet_war_exploded/servletTest

image-20250220212834572

接下来按照我的目录改

image-20250220222241332

image-20250220222253474

非常重要务必跟着我改!!!!!!

idea配置了servlet后访问报错:java.lang.ClassNotFoundException: xxx.xxx.xxx.servlet.ServletDemo1 - 曹婷婷 - 博客园

很详细的解决Tomcat乱码问题-优快云博客

image-20250220224134144

image-20250220222452268

做到这里能访问就是成功!

接下来我们写一个ServletTest

image-20250220213340843

image-20250220135225390

长大眼睛看好了这是service方法后面都会用到!

image-20250220135712216

我们的目的就是重写HttpServlet中的方法比如doGet

因为HttpServlet中写的并不是我们想要的!

image-20250220135825621

//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,还需要给他一个浏览器能够访问的路径;

image-20250220222001635

//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是访问这个webappindex(索引) /s1/ServletTest再去请求那个servlet(这里的就是ServletTest

image-20250220224832117

image-20250220214000661

image-20250220224211857

image-20250220224220097

Servlet

Servlet是由Web服务器调用,web服务器在收到浏览器请求之后:

容器理解成服务器吧!

image-20250220230231369

image-20250220230439765

ServletContext

web容器启动的时候,为每个web程序创建一个对应的ServletContext对象,它代表了当前的web应用。

  • 共享数据

在这个Servlet中保存的数据,可以在另外一个Servlet拿到。

//Servlet上下文
this.getServletContext();

image-20250221084455981

  1. 修改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类,获取上下文中变量的值。

image-20250221085916693

 @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>

image-20250221090317169

image-20250221090512137

Response sendRedirect

一个web资源收到客户端请求后,会通知客户端去访问另外一个web资源,这个过程叫做重定向

image-20250221091746681

常见场景:

  • 用户登录
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>

image-20250221111946023

处理请求:

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

image-20250221112733066

<%@ page contentType="text/html; charset=gb2312"%>
<html>
<head>
</head>
<body>
<h2>Success!</h2>
</form>
</body>
</html>

image-20250221112606355

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.jspsuccess.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>

image-20250221142017011

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留作伏笔

image-20250221171137243

image-20250221171628929

再次刷新就会出现时间。

image-20250221171646879

那么时间是怎么拿到的呢?

响应头

服务端传给客户端

image-20250221171832802

请求头

客户端服务器给的cookie返回服务器

image-20250221171939483

再关掉浏览器再访问网址

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在浏览器一打开的时间就存在了!

image-20250221175142499

image-20250221175524349

Session创建的时候做了啥?

Cookie cookie = new Cookie("JSESSIONID",sessionId);
resp.addCookie(cookie);

image-20250221180108802

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

image-20250221181046007

访问/SessionServlet以后再次 访问/SessionServlet01有数据

image-20250221181148335

总结一下

cookie流程:

image-20250221182229044

session流程:

image-20250221182610484

image-20250221182917426

单点登录SSO

单点登录就是只登录一次,就能无缝的访问多个相关系统和应用

每个单点登录的架构都需要实现一个CAS(Central Authentication Service)服务

  • 服务标识:每个系统应用都会从CAS获得一个唯一标识
  • TGT Ticket:成功通过CAS认证后通过cookie的形式发放给客户端的。比作游乐园门票,有了门票就可以玩游乐园里面的所有项目。
  • Service Ticket(ST):好比是某个具体游玩项目的门票。通过TGT Ticket门票领取具体某个游玩项目的门票ST,才能玩那个项目。

image-20250216193138223

当然这个过程不可能这么简单!简化版!

CAS原理

CAS单点登录原理(包含详细流程,讲得很透彻,耐心看下去一定能看明白!)_java cas 登出逻辑-优快云博客

基本上我是参考该文章来理解的,没有任何抄袭的意思。只是加上我自己的拙见

如果学会了上面的这些知识,下面这个简直是小cas了!

第一次访问www.qiandu.com

image-20250211115328590

标号1:用户访问http://www.qiandu.com,经过第一个过滤器cas提供,在web.xml中配置)AuthenticationFilter。(web.xml都还记得把!)

主要作用:判断是否登录,如果没有登录重定向到认证中心

标号2:www.qiandu.com发现用户没有登录,则返回浏览器重定向地址。

首先可以看到我们请求www.qiandu.com,之后浏览器返回状态码302(302重定向对吧!之前说过的!)

image-20250211123344274

浏览器重定向cas.qiandu.com并且通过get的方式添加参数service,该参数目的是登录成功之后会要重定向回来,因此需要该参数

其实server的值就是编码之后请求www.qiandu.com的地址。

image-20250211123800951


标号3:浏览器接收到重定向之后发起重定向,请求cas.qiandu.com

image-20250211123958371

上图就是标号3的请求,请求的URL标号2返回的URL。之后认证中心就展示登录的页面,等待用户输入用户名密码

标号4:认证中心cas.qiandu.com接收到登录请求,返回登陆页面

image-20250211124103861


标号5:用户cas.qiandu.comlogin页面输入用户名密码提交。注意看from data这个就是账号密码

标号6:服务器接收到用户名密码,则验证是否有效验证逻辑可以使用cas-server提供现成的,也可以自己实现

image-20250211124445157

上图就是标号5的请求,以及标号6的响应了。

cas.qiandu.comcsa-server认证通过之后,会返回给浏览器302重定向的地址就是Referer中的service参数对应的

image-20250211132600667

后边并通过get的方式挟带了一个ticket令牌,这个ticket就是ST数字3处)。

同时会在Cookie中设置一个CASTGC,该cookie是网站cas.qiandu.comcookie,只有访问这个网站才会携带这个cookie过去。

感觉是不是和sessionid相似呢?

image-20250221235746731

Cookie中的CASTGC:向cookie中添加该值的目的是当下次访问cas.qiandu.com时,浏览器将Cookie中的TGC携带到服务器,服务器根据这个TGC,查找与之对应的TGT

从而判断用户是否登录过了,是否需要展示登录页面TGTTGC的关系就像SESSIONCookieSESSIONID的关系。

TGT:Ticket Granted Ticket(俗称大令牌,或者说票根,他可以签发ST)

TGC:Ticket Granted Cookiecookie中的value),存在Cookie中,根据他可以找到TGT

ST:Service Ticket (小令牌),是TGT生成的,每个ST只能使用一次,且有有效期限制。也就是上面数字3处的ticket值。

标号7:浏览器从cas.qiandu.com哪里拿到ticket之后,就根据指示重定向到www.qiandu.com,请求的url就是上面返回的url

image-20250211133257808

标号8:www.qiandu.com在过滤器中会取到ticket的值,然后通过http方式调用cas.qiandu.com验证该ticket是否是有效的。

标号9:cas.qiandu.com接收到ticket之后,验证,验证通过返回结果告诉www.qiandu.comticket有效。

标号10:www.qiandu.com接收到cas-server的返回,知道了用户合法,展示相关资源到用户浏览器上。

image-20250211133432975

总结

只是简要介绍了cas原理、cookieSession,工作应该是完全够用了。

如果要深入学习的话,还是得多敲代码!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值