学习资料来源: B站一个up主”楠哥教你学Java” 以前发布的一个视频
作者: JaneRoad
微信公众号:[0error] 关注可了解更多的知识干货,也可看看生活杂谈。如有问题或建议,欢迎在公众号留言。
大家周末好呀,最近太忙了,不好意思哈。今天分享一篇我以前学习SSO单点登录的笔记,希望对大家有帮助!
单点登录
什么是单点登录:一处登录,处处登录,一处登出,处处登出。
用户只需要登录一次就可以访问所有相互信任的应用系统。
SSO
Single Sign On 就是单点登录。通常是企业业务整合解决方案,使用场景举例:一票通。
原理
-
当用户第一次访问淘宝的时候,因为还没有登录,会被引导到认证中心进行登录。 -
根据用户提供的登录信息,认证系统进行身份验证,如果通过,则登录成功,并返回给用户一个认证的凭据(token)。 -
当用户访问天猫时,就会将这个 token 带上,作为自己认证的凭据。 -
应用系统接收到请求后会把 token 送到认证中心进行校验,检查 token 的合法性。 -
如果通过校验,用户就可以在不用再次登录的情况下访问天猫了。
实现技术
Cookie 单点登录
使用 Cookie 作为媒介,存放用户凭证。
用户登录淘宝之后,返回一个 token,存入客户端的 Cookie 中,当用户访问天猫的时候,会自动带上 Cookie,这样 token 又传给了认证中心,进行校验。
分布式 Session
1、用户第一次登录时,将会话信息,写入分布式 Session。
2、用户再次登录时,获取分布式 Session,判断是否有登录信息,如果没有则返回登录页面。
3、Session 一般存储到 Redis 中,因为它有持久化功能,如果分布式 Session 宕机后,重启之后可以从持久化存储中重新加载会话信息。
SSO 常见方案
OAuth2(第三方登录授权)
第三方系统访问主系统资源,用户无需将主系统的账户告知第三方,只需要通过主系统的授权,第三方就可以使用主系统的资源。
JWT
Json Web Token,是为了在网络应用之间传递信息而执行的一种,基于 JSON 的开放标准,难度较高,需要了解很多协议,偏向底层的东西,需要你基于 JWT 认证协议,自己开放 SSO 服务和权限控制。
CAS
单点登录的 CAS 和并发的 CAS 完全是两码事
中央认证服务,Central Authentication Service
CAS 是耶鲁大学发起的一个开源项目,为 Web 应用系统提供单点登录的解决方案,实现多个系统只需要登录一次,无需重复登录。
-
CAS Server -
CAS Client
Server 和 Client 分别独立部署,Server 主要负责认证工作
Client 负责处理对客户端资源的访问请求,需要登录时,重定向到 Server 进行认证。
1、授权服务器保存一个全局 session,多个客户端各自保存自己的 session。
2、客户端登录时判断自己的 session 是否已经登录,如果没有登录,则重定向到服务器进行授权(带上自己的地址,用于回调)。
3、授权服务器判断全局的 session 是否已经登录,如果未登录则重定向到登录页面,提供用户登录,登录成功之后,授权服务器重定向到客户端,带上 ticket。
4、客户端收到 ticket 后,请求服务器获取用户信息。
5、服务器同意客户端授权后,服务器保存用户信息到全局 session,客户端将用户信息保存至本地 session。
手写单点登录系统架构
Spring Boot + Thymelaf
Thymeleaf 是个什么?
简单说, Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎,它可以完全替代 JSP 。相较与其他的模板引擎,它有如下三个极吸引人的特点:
1.Thymeleaf 在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持 html 原型,然后在 html 标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性,所以 thymeleaf 的模板可以静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示。
2.Thymeleaf 开箱即用的特性。它提供标准和spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、改jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。
3.Thymeleaf 提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
SSO(主工程) 创建三个子工程
-
taobao (客户端) -
tmall (客户端) -
server (服务端)
SSO客户端-淘宝
1、首先配置淘宝客户端的配置文件application.yml(访问端口、thymeleaf 模板、前后缀、标头、编码)
server:
port: 8081
spring:
thymeleaf:
suffix: .html
prefix: classpath:/templates/
servlet:
content-type: text/html
encoding: UTF-8
2、resources下创建templates目录,写入index.html静态页面
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" th:href="@{/layui/css/layui.css}" media="all">
</head>
<body>
<div class="layui-container" style="width: 700px;height: 600px;margin-top: 0px;padding-top: 60px;">
<h1>淘宝首页</h1>
<div style="margin-left: 460px; width: 200px;">
欢迎回来!admin
<a th:href="${serverLogoutUrl}">
<button class="layui-btn layui-btn-warm layui-btn-radius">退出</button>
</a>
</div>
<img width="700px" th:src="@{/images/taobao.png}">
</div>
</body>
</html>
3、static目录导入layui,layui是一个前端框架
static目录导入一个图片模拟淘宝首页
4、创建运行类TaobaoApplication
package com.janeroad;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class TaobaoApplication {
public static void main(String[] args) {
SpringApplication.run(TaobaoApplication.class,args);
}
}
5、创建控制器 TaobaoHandler,处理异步请求
package com.janeroad.controller;
import com.janeroad.util.SSOClientUtil;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;
@Controller
public class TaobaoHandler {
@GetMapping("/taobao")
public String index(Model model){
model.addAttribute("serverLogoutUrl", SSOClientUtil.getServerLogoutUrl());
return "index";
}
@RequestMapping("/logout")
public String logout(HttpSession session){
session.invalidate();
return "redirect:/taobao";
}
}
6、创建拦截器TaobaoInterceptor,继承与HandelerInterceptor,用于当请求服务端页面时判断用户是否登录,如果登录过放行,如果未登录跳转登录页面
package com.janeroad.interceptor;
import com.janeroad.util.HttpUtil;
import com.janeroad.util.SSOClientUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.thymeleaf.util.StringUtils;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
@Slf4j
public class TaobaoInterceptor implements HandlerInterceptor {
/**
* 功能描述:
* true 放行
* false 不放行
* @Param: [request, response, handler]
* @Return: boolean
* @Author: JaneRoad
* @Date: 2020/3/29 15:30
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1、判断是否已经登陆
HttpSession session =request.getSession();
Boolean isLogin =(Boolean) session.getAttribute("isLogin");
if(isLogin!=null && isLogin){
return true;
}
//2、判断 token
String token=request.getParameter("token");
if(!StringUtils.isEmpty(token)){
//验证token
log.info("token存在,需要验证");
//发起验证
String httpUrl = SSOClientUtil.SERVER_HOST_URL+"/verify";
HashMap params = new HashMap<>();
params.put("token",token);
params.put("clientLogoutUrl",SSOClientUtil.getClientLogoutUrl());
String isVerify = HttpUtil.sendHttpRequest(httpUrl,params);
if("true".equals(isVerify)){
log.info("token验证通过,token={}",token);
//token保存到本地Cookie
Cookie cookie = new Cookie("token",token);
response.addCookie(cookie);
session.setAttribute("isLogin",true);
return true;
}
}
//3、跳转到认证中心进行登录
SSOClientUtil.redirectToCheckToken(request, response);
return false;
}
}
7、创建工具类SSOClientUtil
package com.janeroad.util;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Properties;
public class SSOClientUtil {
private static Properties properties = new Properties();
public static String SERVER_HOST_URL;
public static String CLIENT_HOST_URL;
static {
try {
properties.load(SSOClientUtil.class.getClassLoader().getResourceAsStream("sso.properties"));
SERVER_HOST_URL = properties.getProperty("server.host.url");
CLIENT_HOST_URL = properties.getProperty("client.host.url");
} catch (IOException e) {
e.printStackTrace();
}
}
//跳转到认证中心
public static void redirectToCheckToken(HttpServletRequest request, HttpServletResponse response){
StringBuffer url=new StringBuffer();
url.append(SERVER_HOST_URL)
.append("/checkToken?redirectUrl=")
.append(CLIENT_HOST_URL)
.append(request.getServletPath());
try {
response.sendRedirect(url.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
public static String getServerLogoutUrl(){
return SERVER_HOST_URL+"/logout";
}
public static String getClientLogoutUrl(){
return CLIENT_HOST_URL+"/logout";
}
}
8、resources下写入一个配置文件sso.properties,用于记录服务端地址
server.host.url=http://localhost:8080
client.host.url=http://localhost:8081
9、创建工具类HttpUtil
package com.janeroad.util;
import org.springframework.util.StreamUtils;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Map;
public class HttpUtil {
/**
* id=1
* name=tom
* {id=1,name=tom} id=1&name=tom
* @param httpUrl
* @param params
* @return
*/
public static String sendHttpRequest(String httpUrl, Map params){
try {
URL url = new URL(httpUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
if(params!=null && params.size()>0){
StringBuffer stringBuffer = new StringBuffer();
for(Map.Entry entry:params.entrySet()){
stringBuffer.append("&")
.append(entry.getKey())
.append("=")
.append(entry.getValue());
}
connection.getOutputStream().write(stringBuffer.substring(1).toString().getBytes("UTF-8"));
}
connection.connect();
String response = StreamUtils.copyToString(connection.getInputStream(), Charset.forName("UTF-8"));
return response;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
}
return null;
}
}
SSO-服务端
1、首先配置服务端的配置文件application.yml(访问端口、thymeleaf 模板、前后缀、标头、编码)
server:
port: 8080
spring:
thymeleaf:
prefix: classpath:/templates/
suffix: .html
servlet:
content-type: text/html
encoding: UTF-8
2、resources下创建templates目录,写入index.html静态页面
<!DOCTYPE html>
<html lang="en">
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/layui/css/layui.css" media="all">
</head>
<body>
<div class="layui-container" style="width: 500px;height: 330px;margin-top: 130px;border: 1px solid #009688;padding-top: 60px;border-radius: 15px">
<form class="layui-form" action="/login" method="post">
<input type="hidden" name="redirectUrl" th:value="${redirectUrl}">
<div class="layui-form-item">
<label class="layui-form-label">用户名</label>
<div class="layui-inline">
<input type="text" name="username" lay-verify="username" autocomplete="off" placeholder="请输入用户名" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">密码</label>
<div class="layui-inline">
<input type="password" name="password" lay-verify="password" placeholder="请输入密码" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<button class="layui-btn" lay-submit="" lay-filter="demo2" style="margin-left: 160px;">登陆</button>
</div>
</form>
</div>
<script src="/layui/layui.js" charset="utf-8"></script>
<script>
layui.use(['form'], function(){
var form = layui.form;
//自定义验证规则
form.verify({
username: function(value){
if(value.length == 0){
return '用户名不能为空';
}
}
,password: [/(.+){6,12}$/, '密码必须6到12位']
});
});
</script>
</body>
</html>
3、同客户端,static目录导入layui,layui是一个前端框架
4、创建运行类ServerApplication
package com.janeroad;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class,args);
}
}
5、创建控制器 ServerHandler,处理异步请求
package com.janeroad.controller;
import com.janeroad.db.MockDB;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.thymeleaf.util.StringUtils;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@Controller
@Slf4j
public class ServerHandler {
/**
* 功能描述: 第一次登录验证
* 〈〉
* @Param: [redirectUrl, session, model]
* @Return: java.lang.String
* @Author: JaneRoad
* @Date: 2020/3/29 16:21
*/
@RequestMapping("/checkToken")
public String checkToken(String redirectUrl, HttpSession session, Model model, HttpServletRequest request)
{
//获取token
String token = (String) session.getServletContext().getAttribute("token");
if(StringUtils.isEmpty(token)){
model.addAttribute("redirectUrl",redirectUrl);
return "login";
}else{
//验证token
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
if(cookie.getValue().equals(token)){
//验证通过,返回客户端
log.info("token验证通过");
return "redirect:"+redirectUrl+"?token="+token;
}
}
}
model.addAttribute("redirectUrl",redirectUrl);
return "login";
}
@PostMapping("/login")
public String login(String username,
String password,
String redirectUrl,
HttpSession session,
Model model){
//判断登录
if("admin".equals(username) && "123123".equals(password)){
//1、创建token
String token = UUID.randomUUID().toString();
log.info("token创建成功!token={}",token);
//2、token保存到全局会话中
session.getServletContext().setAttribute("token",token);
//3、token保存到数据库
MockDB.tokenSet.add(token);
//4、返回客户端
return "redirect:"+redirectUrl+"?token="+token;
}else{
log.error("用户名密码错误!username={},password={}",username,password);
model.addAttribute("redirectUrl",redirectUrl);
return "login";
}
}
@RequestMapping("/verify")
@ResponseBody
public String verifyToken(String token,String clientLogoutUrl){
if(MockDB.tokenSet.contains(token)){
Set set = MockDB.clientLogoutUrlMap.get(token);
if(set == null){
set = new HashSet<>();
}
set.add(clientLogoutUrl);
MockDB.clientLogoutUrlMap.put(token,set);
return "true";
}
return "false";
}
@RequestMapping("/logout")
public String logout(HttpSession session){
session.invalidate();
return "login";
}
}
6、创建监听器,登出的时候账号销毁的时候需要操作
package com.janeroad.listener;
import com.janeroad.db.MockDB;
import com.janeroad.util.HttpUtil;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.util.Iterator;
import java.util.Set;
@WebListener
public class SessionListener implements HttpSessionListener {
@Override
public void sessionDestroyed(HttpSessionEvent se) {
//1、删除全局会话中的token
//2、删除数据库的用户信息
//3、通知所有客户端销毁session
String token = (String) se.getSession().getServletContext().getAttribute("token");
se.getSession().getServletContext().removeAttribute("token");
MockDB.tokenSet.remove(token);
Set set = MockDB.clientLogoutUrlMap.get(token);
Iterator iterator = set.iterator();
while(iterator.hasNext()){
HttpUtil.sendHttpRequest(iterator.next(),null);
}
MockDB.clientLogoutUrlMap.remove(token);
}
}
7、创建监听器配置ListenerConfig
package com.janeroad.config;
import com.janeroad.listener.SessionListener;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class ListenerConfig implements WebMvcConfigurer {
@Bean
public ServletListenerRegistrationBean bean(){
ServletListenerRegistrationBean bean = new ServletListenerRegistrationBean();
bean.setListener(new SessionListener());
return bean;
}
}
8、创建MockDB模拟数据库
package com.janeroad.db;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class MockDB{
//记录token
public static Set tokenSet=new HashSet<>();
//客户端登出地址
public static Map> clientLogoutUrlMap = new HashMap<>();
}
9、创建HttpUtil工具类
package com.janeroad.util;
import org.springframework.util.StreamUtils;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Map;
public class HttpUtil {
/**
* id=1
* name=tom
* {id=1,name=tom} id=1&name=tom
* @param httpUrl
* @param params
* @return
*/
public static String sendHttpRequest(String httpUrl, Map params){
try {
URL url = new URL(httpUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
if(params!=null && params.size()>0){
StringBuffer stringBuffer = new StringBuffer();
for(Map.Entry entry:params.entrySet()){
stringBuffer.append("&")
.append(entry.getKey())
.append("=")
.append(entry.getValue());
}
connection.getOutputStream().write(stringBuffer.substring(1).toString().getBytes("UTF-8"));
}
connection.connect();
String response = StreamUtils.copyToString(connection.getInputStream(), Charset.forName("UTF-8"));
return response;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
}
return null;
}
}
SSO客户端-Tmall
天猫客户端和淘宝的相似
1、首先配置淘宝客户端的配置文件application.yml(访问端口、thymeleaf 模板、前后缀、标头、编码)
server:
port: 8082
spring:
thymeleaf:
prefix: classpath:/templates/
suffix: .html
servlet:
content-type: text/html
encoding: UTF-8
2、resources下创建templates目录,写入index.html静态页面
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" th:href="@{/layui/css/layui.css}" media="all">
</head>
<body>
<div class="layui-container" style="width: 700px;height: 600px;margin-top: 0px;padding-top: 60px;">
<h1>天猫首页</h1>
<div style="margin-left: 460px; width: 200px;">
欢迎回来!admin
<a th:href="${serverLogoutUrl}">
<button class="layui-btn layui-btn-warm layui-btn-radius">退出</button>
</a>
</div>
<img width="700px" th:src="@{/images/tmall.png}">
</div>
</body>
</html>
3、static目录导入layui,layui是一个前端框架。image下导入图片,模拟天猫首页
4、创建运行类TmallApplication
package com.janeroad;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class TmallApplication {
public static void main(String[] args) {
SpringApplication.run(TmallApplication.class,args);
}
}
5、创建控制器 TmallHandler,处理异步请求
package com.janeroad.controller;
import com.janeroad.util.SSOClientUtil;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;
@Controller
public class TmallHandler {
@GetMapping("/tmall")
public String index(Model model){
model.addAttribute("serverLogoutUrl", SSOClientUtil.getServerLogoutUrl());
return "index";
}
@RequestMapping("/logout")
public String logout(HttpSession session){
session.invalidate();
return "redirect:/tmall";
}
}
6、创建拦截器TmallInterceptor,继承与HandelerInterceptor,用于当请求服务端页面时判断用户是否登录,如果登录过放行,如果未登录跳转登录页面
package com.janeroad.interceptor;
import com.janeroad.util.HttpUtil;
import com.janeroad.util.SSOClientUtil;
import lombok.extern.slf4j.Slf4j;
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;
import java.util.HashMap;
@Slf4j
public class TmallInterceptor implements HandlerInterceptor {
/**
* true 放行
* false 不放行
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1、判断是否已经登录
HttpSession session = request.getSession();
Boolean isLogin = (Boolean) session.getAttribute("isLogin");
if (isLogin != null && isLogin) {
return true;
}
//2、判断token
String token = request.getParameter("token");
if (!StringUtils.isEmpty(token)) {
//验证token
log.info("token存在,需要验证");
//发起验证
String httpUrl = SSOClientUtil.SERVER_HOST_URL + "/verify";
HashMap params = new HashMap<>();
params.put("token", token);
params.put("clientLogoutUrl",SSOClientUtil.getClientLogoutUrl());
String isVerify = HttpUtil.sendHttpRequest(httpUrl, params);
if ("true".equals(isVerify)) {
log.info("token验证通过,token={}", token);
//token保存到本地Cookie
Cookie cookie = new Cookie("token", token);
response.addCookie(cookie);
session.setAttribute("isLogin", true);
return true;
}
}
//3、跳转到认证中心进行登录
SSOClientUtil.redirectToCheckToken(request, response);
return false;
}
}
7、创建工具类SSOClientUtil
package com.janeroad.util;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Properties;
public class SSOClientUtil {
private static Properties properties = new Properties();
public static String SERVER_HOST_URL;
public static String CLIENT_HOST_URL;
static {
try {
properties.load(SSOClientUtil.class.getClassLoader().getResourceAsStream("sso.properties"));
SERVER_HOST_URL = properties.getProperty("server.host.url");
CLIENT_HOST_URL = properties.getProperty("client.host.url");
} catch (IOException e) {
e.printStackTrace();
}
}
//跳转到认证中心
public static void redirectToCheckToken(HttpServletRequest request, HttpServletResponse response) {
StringBuffer url = new StringBuffer();
url.append(SERVER_HOST_URL)
.append("/checkToken?redirectUrl=")
.append(CLIENT_HOST_URL)
.append(request.getServletPath());
try {
response.sendRedirect(url.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
public static String getServerLogoutUrl(){
return SERVER_HOST_URL+"/logout";
}
public static String getClientLogoutUrl(){
return CLIENT_HOST_URL+"/logout";
}
}
创建工具类HttpUtil
package com.janeroad.util;
import org.springframework.util.StreamUtils;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Map;
public class HttpUtil {
/**
* id=1
* name=tom
* {id=1,name=tom} id=1&name=tom
* @param httpUrl
* @param params
* @return
*/
public static String sendHttpRequest(String httpUrl, Map params){
try {
URL url = new URL(httpUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
if(params!=null && params.size()>0){
StringBuffer stringBuffer = new StringBuffer();
for(Map.Entry entry:params.entrySet()){
stringBuffer.append("&")
.append(entry.getKey())
.append("=")
.append(entry.getValue());
}
connection.getOutputStream().write(stringBuffer.substring(1).toString().getBytes("UTF-8"));
}
connection.connect();
String response = StreamUtils.copyToString(connection.getInputStream(), Charset.forName("UTF-8"));
return response;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
}
return null;
}
}
8、resources下写入一个配置文件sso.properties,用于记录服务端地址
server.host.url=http://localhost:8080
client.host.url=http://localhost:8082
最终实现效果
访问localhost://8081/taobao
,模拟访问淘宝跳转到登录页面
访问localhost://8082/tmall
,模拟访问天猫跳转到登录页面
淘宝输入用户名密码,跳转淘宝首页
刷新localhost://8082/tmall
,天猫自动登录进入首页
在天猫和淘宝任一界面退出账号,另一个界面随之退出,从而实现一处登录处处登录,一处登出处处登出。
原文始发于微信公众号(JaneRoad):SSO单点登录实战
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/22968.html