单点登陆sso实现(基于全局session实现)

本篇博客实现借鉴自:大厂架构演进实战之手写 CAS 单点登录

如果不想按下面的步骤一个一个粘贴,我也提供了github地址:https://github.com/XuBaozhao/sso

一、实现目标:

登陆淘宝,跳转登陆页面,登陆后,进入淘宝主页,再次登陆天猫,发现不用登陆,直接进入了天猫主页。

我省略了和数据库打交道的一点,并且也省略了验证token相同的环节,因为只是简单的熟悉流程,细节问题并不考虑在内。

看下面的结果展示,你就明白了。

(1)taobao 首先访问,被拦截,检测到没有 token,进入 ssoserver 的 checktoken 方法,此时全局 token 为空,进入登录页面,完成登录逻辑,生成 token 存入全局 token,并且将 token 存入数据库,再带着这个 token 返回 taobao。

(2)进入 taobao 拦截器,有 token,进行验证,进入 ssoserver 的 verify 方法,从数据库中查询,token 存在,则返回 true。

(3)回到 taobao 拦截器,结果为 true,将 token 存入 Cookie(给 tmall 检测使用),并将 isLogin = true 存入本地 session,返回 true,通过拦截器,进入页面,taobao 登录逻辑完成。

(4)tmall 访问,被拦截,检测到没有 token,进入 ssoserver 的 checktoken 方法,此时全局 token 存在,则对比 Cookie,如果 Cookie 中没有相等的 token,则登录,如果有相等的 token,则表示其他子项目(taobao)已登录过,tmall 不需要再次登录,带着这个 token 返回 tmall。

(5)进入 tmall 拦截器,有 token,进行验证,进入 ssoserver 的 verify 方法,从数据库中查询,token 存在,则返回 true。

(6)回到 tmall 拦截器,结果为 true,将 token 存入 Cookie,并将 isLogin = true 存入本地 session,返回 true,通过拦截器,进入页面,tmall 登录逻辑完成。

单点登陆sso实现(基于全局session实现)_第1张图片
 

二、结果展示:

1、url输入以下:

2、enter之后:

单点登陆sso实现(基于全局session实现)_第2张图片

3、输入1和1,登陆:

 4、进入淘宝主页:

5、访问天猫:

6、enter后:

7、再次访问淘宝和天猫,仍然直接进入主页,不会登陆

 

三、详细步骤

第一步:整体布局

单点登陆sso实现(基于全局session实现)_第3张图片

  • ssodemo:父项目,啥也没做
  • ssoclienttaobao:提供淘宝访问服务
  • ssoclienttmall:提供天猫访问服务
  • ssoserver:sso单点登录服务器,提供登陆和验证服务 

 

第二步:先看ssoclienttaobao项目

单点登陆sso实现(基于全局session实现)_第4张图片

 

1、pom配置



	4.0.0
	
		org.springframework.boot
		spring-boot-starter-parent
		2.3.4.RELEASE
		 
	
	com.bupt
	ssoclienttaobao
	0.0.1-SNAPSHOT
	ssoclienttaobao
	Demo project for Spring Boot

	
		1.8
	

	
		
			org.springframework.boot
			spring-boot-starter
		

		
			org.springframework.boot
			spring-boot-starter-web
		

		
			org.springframework.boot
			spring-boot-starter-thymeleaf
		
		
		
			org.springframework.boot
			spring-boot-starter-test
			test
			
				
					org.junit.vintage
					junit-vintage-engine
				
			
		

	

	
		
			
				org.springframework.boot
				spring-boot-maven-plugin
			
		
	


 

2、config配置

1、首先配置RestTemplate,用于进程远程RPC服务调用

package com.bupt.ssoclienttaobao.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ApplicationContextConfig {

    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

2、配置拦截器:

拦截url = taobao的请求

package com.bupt.ssoclienttaobao.configuration;

import com.bupt.ssoclienttaobao.interceptor.TaobaoInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class InterceptorConfiguration implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        String[] addPathPattrens = {"/taobao"};
        registry.addInterceptor(new TaobaoInterceptor()).addPathPatterns(addPathPattrens);
    }
}

 

3、controller控制器

package com.bupt.ssoclienttaobao.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@Controller
public class TaobaoController {


    public static final String PAYMENT_URL = "http://localhost:8081";

    @Resource
    private RestTemplate restTemplate;

    @GetMapping("/index")
    public String index2(){
        return "index";
    }

    // 进入淘宝页面
    @GetMapping("/taobao")
    public String index(){
        return "index";
    }
}

 

4、interceptor拦截器

作用:该拦截器用于访问淘宝页面之前,首先判断自己是否登陆过(session中isLogin不空) and 天猫是否登陆过(token不空),如果以上有一点满足,则直接访问,否则进入ssoserver的登陆页面。

package com.bupt.ssoclienttaobao.interceptor;

import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class TaobaoInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //判断会话是否存在
        HttpSession session = request.getSession();
        Boolean isLogin = (Boolean) session.getAttribute("isLogin");

        // 如果session中isLogin == true,说明自己登陆过了,直接访问
        if(isLogin!=null && isLogin){
            return true;
        }

        //判断token
        String token = request.getParameter("token");

        // 如果token不为空,说明自己没登录,别人登陆过了,自己保存信息,也是返回true
        if(!StringUtils.isEmpty(token)){
                Cookie cookie = new Cookie("token", token);
                response.addCookie(cookie);
                session.setAttribute("isLogin", true);
                return true;
        }

        // token为空,登录认证
        response.sendRedirect("http://localhost:8081/checkToken?url=http://localhost:8080/taobao");
        return false;
    }
}

 

5、配置文件:解析html

#thymeleaf start
#视图解析器的前缀放在这个文件夹
spring.thymeleaf.prefix=classpath:/templates/
#后缀
spring.thymeleaf.suffix=.html
#模式
spring.thymeleaf.mode=LEGACYHTML5
spring.thymeleaf.servlet.content-type=text/html
#编码格式
spring.thymeleaf.encoding=utf-8
#不用缓存
spring.thymeleaf.cache=false
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
#thymeleaf end

 

6、HTML页面




    
    登录
    


淘宝主页

 

第二步:ssoserver项目

单点登陆sso实现(基于全局session实现)_第5张图片

 

1、pom



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.3.4.RELEASE
         
    
    com.bupt
    ssoserver
    0.0.1-SNAPSHOT
    ssoserver
    Demo project for Spring Boot

    
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        

        
            net.sourceforge.nekohtml 
            nekohtml 
            1.9.22 
        


        
            org.springframework.boot
            spring-boot-starter-test
            test
            
                
                    org.junit.vintage
                    junit-vintage-engine
                
            
        

    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


 

 2、config(没用到......)

 

3、controller

package com.bupt.ssoserver.controller;

import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.UUID;

@Controller
public class Testcontroller {

    // 进入登陆页面
    @GetMapping("/login")
    public String index(){
        return "login";
    }

    // 判断登陆逻辑
    @PostMapping("userlogin")
    public String login(HttpServletRequest httpServletRequest, HttpSession session) throws IOException {
        String username = httpServletRequest.getParameter("username");
        String password = httpServletRequest.getParameter("password");

        if(username.equals("1") && password.equals("1")){
            String token = UUID.randomUUID().toString();
            // 设置servlet上下文信息
            session.getServletContext().setAttribute("token", token);
            // 进入淘宝主页
            return "redirect:"+"http://localhost:8080/taobao"+"?token="+token;
        }
        return "error";
    }

    @GetMapping("/checkToken")
    public String checkToken(HttpServletRequest request, HttpSession session){

        String url = request.getParameter("url");
        String token = (String) session.getServletContext().getAttribute("token");

        // 如果token空,登陆
        if(StringUtils.isEmpty(token)){
            return "login";
        }else{
            Cookie[] cookies = request.getCookies();
            for (Cookie cookie : cookies) {
                if(cookie.getValue().equals(token)){
                    return "redirect:"+url+"?token="+token;
                }
            }
            return "login";
        }
    }
}

 

4、配置

server.port=8081

#thymeleaf start
#视图解析器的前缀放在这个文件夹
spring.thymeleaf.prefix=classpath:/templates/
#后缀
spring.thymeleaf.suffix=.html
#模式
spring.thymeleaf.mode=LEGACYHTML5
spring.thymeleaf.servlet.content-type=text/html
#编码格式
spring.thymeleaf.encoding=utf-8
#不用缓存
spring.thymeleaf.cache=false
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
#thymeleaf end

 

5、Html

login.html



    
    Title


请输入用户名与密码登录
用户名:
密   码:

error.html




    
    登录
    


error

 

第三步:ssoclenttmall项目(基本上和taobao全部相似)

单点登陆sso实现(基于全局session实现)_第6张图片

 

1、pom



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.3.4.RELEASE
         
    
    com.bupt
    ssoclienttmall
    0.0.1-SNAPSHOT
    ssoclienttmall
    Demo project for Spring Boot

    
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
            
                
                    org.junit.vintage
                    junit-vintage-engine
                
            
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


 

2、config

package com.bupt.ssoclienttmall.configuration;

        import org.springframework.context.annotation.Bean;
        import org.springframework.context.annotation.Configuration;
        import org.springframework.web.client.RestTemplate;

@Configuration
public class ApplicationContextConfig {

    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}
package com.bupt.ssoclienttmall.configuration;

import com.bupt.ssoclienttmall.interceptor.TmallInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class InterceptorConfiguration implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        String[] addPathPattrens = {"/tmall"};
        registry.addInterceptor(new TmallInterceptor()).addPathPatterns(addPathPattrens);
    }
}

 

3、controller

package com.bupt.ssoclienttmall.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class TmallController {

    @GetMapping("/tmall")
    public String index(){
        return "index";
    }
}

 

4、拦截器

package com.bupt.ssoclienttmall.interceptor;

import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class TmallInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断会话是否存在
        HttpSession session = request.getSession();
        Boolean isLogin = (Boolean) session.getAttribute("isLogin");
        // 如果session中isLogin == true,直接访问,不用拦截
        if(isLogin!=null && isLogin){
            return true;
        }
        //判断token
        String token = request.getParameter("token");

        // 如果token不为空
        if(!StringUtils.isEmpty(token)){
                //验证通过
                Cookie cookie = new Cookie("token", token);
                response.addCookie(cookie);
                session.setAttribute("isLogin", true);
                return true;
        }

        //token为空,登录认证
        response.sendRedirect("http://localhost:8081/checkToken?url=http://localhost:8082/tmall");
        // SSOClientUtil.redirectToCheckToken(request, response);
        return false;
    }
}

 

5、配置

server.port=8082

#thymeleaf start
#视图解析器的前缀放在这个文件夹
spring.thymeleaf.prefix=classpath:/templates/
#后缀
spring.thymeleaf.suffix=.html
#模式
spring.thymeleaf.mode=LEGACYHTML5
spring.thymeleaf.servlet.content-type=text/html
#编码格式
spring.thymeleaf.encoding=utf-8
#不用缓存
spring.thymeleaf.cache=false
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
#thymeleaf end

 

6、html




    
    登录
    


天猫主页

 

......总算记录完了,我发现写文档的过程比写项目还痛苦....

你可能感兴趣的:(Springboot,单点登陆sso实现,基于全局session实现)