轻松掌握SSO单点登录,就看这一篇文章

一、引言

众所周知,一个网页系统,最基础的功能就是登录,作为一名JAVA程序员,从写下Hello Word 到变成一个技术大牛的这个过程中,登录功能不一定是写的最多,但是一定会是最常见的,本篇文章简单介绍了一下SSO的概念及原理,然后使用SpringBoot实现了一个简单的SSO系统。系统使用token的形式,依靠cookie携带token向sso服务器进行验证,验证通过后允许访问请求地址。

二、SSO介绍

众所周知,我们在最开始写业务的时候,可能就只有一个模块,但是随着开发时间的增加,代码会越来越多,会十分的冗余,那么这个时候我们就会把代码拆分成一个又一个的小模块,每一个模块就是一个系统,比方说我们做了一个电商系统,他里面分了购物车系统,商品系统,购买系统等等,那么我们登录后,访问另一个系统的时候,如果还要再一次的登录的话,就会十分的麻烦,所以在这里我们引进了SSO单点登录系统,只要一个系统登陆成功,另一个系统就不需要登录了。

三、常见例子

我们日常生活中用的最多的电商APP估计是淘宝,在这里我们用淘宝举一个例子

首先,我们登录淘宝的主界面,并且登录

点击跳转淘宝主界面

在这里插入图片描述
在这里,我们可以看见淘宝的域名,taobao.com,这个时候,我们来看看购物车,我们会发现,进入购物车菜单后,网站的域名发生了变化
在这里插入图片描述
那么,我们就可以知道,在这里,就发生了单点登录,只要我们登录了主界面,在访问其他系统,比如说购物车,收藏夹什么的,也算我们登录了,那么就不需要再做第二遍,这样节省了很多的事情,那么我们今天就要学习这一点是如何做到的。

三、SSO代码实现

目前常见的登录有两种,一种是把用户信息存在session中,在镜进行操作的时候判断session是否存在,还有一种是通过token来进行判断。我们知道session是不共享的,那么,我们是不是可以把token存在cookie中,当一个系统登录了,去访问另一个系统的时候,我们判断一下token是否正确,如果正确,就放行,错误,则拦截,在这里我们简单的实现一下

给本机赋域名

在写代码之前,我们要先给我们的主机赋予一个域名,这样才方便我们接下来的工作

我们先查看一下我们所在局域网的ip

在这里插入图片描述

打开我的电脑,找到此路径:C:\Windows\System32\drivers\etc

在这里插入图片描述

然后打开host文件,进行编写,域名可以自己随便取名字,搞完后保存退出

在这里插入图片描述

编写代码

我们需要两个服务来模拟,所以我们先自己建立好下面两个文件,然后给client设置端口8081,server设置8082

在这里插入图片描述

然后,我们把其余的代码补充,先是client下的

User类

package com.znb.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String username;
    private String password;
}

LoginCacheUtil

package com.znb.utils;



import com.znb.pojo.User;

import java.util.HashMap;
import java.util.Map;

public class LoginCacheUtil {
    public static Map<String , User> loginUser = new HashMap<>();
}


LoginController

package com.znb.controller;


import com.znb.pojo.User;
import com.znb.utils.LoginCacheUtil;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.thymeleaf.util.StringUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;


@Controller
@RequestMapping("/login")
public class LoginController {
    private static Set<User> dbUsers;
    static {
        dbUsers = new HashSet<>();
        dbUsers.add(new User(0,"xiaoyan","000000"));
        dbUsers.add(new User(1,"tangsan","000000"));
        dbUsers.add(new User(2,"yecheng","000000"));
    }

    @PostMapping
    public String doLogin(User user, HttpSession session, HttpServletResponse response){


        //模拟从数据库中通过登陆的用户名和密码去查找数据库中用户
        Optional<User> first = dbUsers.stream().filter(dbUser -> dbUser.getUsername().equals(user.getUsername()) &&
                dbUser.getPassword().equals(user.getPassword()))
                .findFirst();
        //判断用户是否登陆
        if(first.isPresent()){
            //保存用户的登录信息
            String token = UUID.randomUUID().toString();
            Cookie cookie = new Cookie("TOKEN",token);
            cookie.setDomain("codeicee.com");
            response.addCookie(cookie);
            LoginCacheUtil.loginUser.put(token,first.get());
        }
        else{
            //登陆失败
            session.setAttribute("msg","用户名或密码错误");
            return "login";
        }
        //重定向到target地址
        return "index" ;
    }

    @GetMapping("info")
    @ResponseBody
    public ResponseEntity<User> getUserInfo(String token){
        if(!StringUtils.isEmpty(token)){
            User user = LoginCacheUtil.loginUser.get(token);
            return ResponseEntity.ok(user);
        }else {
            return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
        }
    }
}


ViewController

package com.znb.controller;


import com.znb.pojo.User;
import com.znb.utils.LoginCacheUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.thymeleaf.util.StringUtils;

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

/**
 * 页面跳转逻辑
 */
@Controller
@RequestMapping("/view")
public class ViewController {


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


    /**
     * 跳转到登录页面
     * @return
     */
    @GetMapping("/login")
    public String toLogin(@RequestParam(required = false,defaultValue = "")String target,
                          HttpSession session,
                          @CookieValue(required = false,value = "TOKEN")Cookie cookie){

        if(StringUtils.isEmpty(target)){
            target = "http://www.codeicee.com:8081";
        }
        //如果是已经登陆的用户再次访问登录页面,需要重定向
        if(cookie != null){
            //token
            String value = cookie.getValue();
            User user = LoginCacheUtil.loginUser.get(value);
            if(user != null){
                return "product";
            }
        }


        //重定向地址
        session.setAttribute("target",target);
        return "login";
    }
}



index

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>首页</h1>
</body>
</html>

login

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8"/>
    <title>Login Module</title>
</head>
<body>
<h1>欢迎来到登录页面</h1>
<p style="color: red;" th:text="${session.msg}"></p>
<form action="/login" method="POST">
    用户名:<input name="username" value=""/>
    密码:<input name="password" value=""/>
    <button type="submit">登录</button>
</form>
</body>
</html>

product

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>产品</h1>
</body>
</html>

然后是server

ViewController

package com.znb.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.RestTemplate;
import org.thymeleaf.util.StringUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;
import java.util.Map;

@Controller
@RequestMapping("/view")
public class ViewController {

    @Autowired
    private RestTemplate restTemplate;

    private final String USER_INFO_ADDRESS = "http://codeicee.com:8081/login/info?token=";


    @GetMapping("/index")
    public String toIndex(@CookieValue(required = false,value = "TOKEN") Cookie cookie,
                          HttpSession session){
        if(cookie != null){
            String token = cookie.getValue();
            if(!StringUtils.isEmpty(token)){
                Map result = restTemplate.getForObject(USER_INFO_ADDRESS + token,Map.class);
                session.setAttribute("loginUser",result);
            }
        }
        return "index";
    }
}


把两个项目都启动后,我们会发现,当client登录后server的也登录成功了

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值