IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 手撸SSO单点登录(四)登录验证-首次登录 -> 正文阅读

[Java知识库]手撸SSO单点登录(四)登录验证-首次登录

一、目标

前一章节讲解了各应用未登录的系统统一跳转至SSO统一登录页面。当输入用户名、密码后点击登录流程是怎么实现的。这一章节的目标主要是讲解OA(这里代表client.sso.com:8082)经过统一登录后怎么回跳至OA页面。

二 、系统UML工程类图

在这里插入图片描述

三、代码实现

a. com.yuantai.controller.LoginController

@RequestMapping(method = RequestMethod.POST)
    public String login(
            @RequestParam(value = SsoConstant.REDIRECT_URI, required = true) String redirectUri,
            @RequestParam(value = Oauth2Constant.APP_ID, required = true) String appId,
            @RequestParam String username,
            @RequestParam String password,
            HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {

        if(!appService.exists(appId)) {
            request.setAttribute("errorMessage", "非法应用");
            return goLoginPath(redirectUri, appId, request);
        }

        Result<SsoUser> result = userService.login(username, password);
        if (!result.isSuccess()) {
            request.setAttribute("errorMessage", result.getMessage());
            return goLoginPath(redirectUri, appId, request);
        }

        String tgt = sessionManager.setUser(result.getData(), request, response);
        return generateCodeAndRedirect(redirectUri, tgt);
    }

1、 输入(用户名、密码)点击登录,首次调用的是/login方法(SmartSsoConfig配置了无需拦截此url)
2、调用com.yuantai.session.TicketGrantingTicketManagersessionManager.setUser()

public String setUser(SsoUser user, HttpServletRequest request, HttpServletResponse response) {
        String tgt = getCookieTgt(request);
        if (StringUtils.isEmpty(tgt)) {
            // cookie中没有 生成一个tgt
            tgt = ticketGrantingTicketManager.generate(user);

            // TGT存cookie,和Cas登录保存cookie中名称一致为:TGC
            CookieUtils.addCookie(AppConstant.TGC, tgt, "/", request, response);
        }
        else if(ticketGrantingTicketManager.getAndRefresh(tgt) == null){
            ticketGrantingTicketManager.create(tgt, user);
        }
        else {
            ticketGrantingTicketManager.set(tgt, user);
        }
        return tgt;
    }

当进入if(StringUtils.isEmpty(tgt))判断时getCookieTgt(request)获取的tgt为空(/login登录只传了用户名与密码并无其他信息)所以此判断为true进去方法体代码中、此方法体作用如下:

  1. 生成一个管理端的登录凭证TGT
  2. 把凭证与用户信息存储内存Map(TGT,用户信息)
  3. 把凭证等信息放入Cookie中

3、调用com.yuantai.controller.BaseLoginControllergenerateCodeAndRedirect(redirectUri, tgt)方法

String generateCodeAndRedirect(String redirectUri, String tgt) throws UnsupportedEncodingException {
        // 生成授权码
        String code = codeManager.generate(tgt, true, redirectUri);
        return "redirect:" + authRedirectUri(redirectUri, code);
    }
  1. 生成临时授权码code,并把code与codeContent内容存入map(code,content内存)
  2. 后台发起重定向请求redirect:http://client.sso.com:8082/?code=code-2f243fd967e840288ddb089611cb31c8记住这里是后端的重定向请求(前端无url变动)与response.sendRedirect(loginUrl)(前端会看到url变动)

4、跳转到OA系统进入com.yuantai.filter.LoginFilter请求拦截、进入isAccessAllowed方法的if (code != null)方法体

@Override
    public boolean isAccessAllowed(HttpServletRequest request, HttpServletResponse response) throws IOException {
        SessionAccessToken sessionAccessToken = SessionUtils.getAccessToken(request);
        // 本地Session中已存在,且accessToken没过期或者refreshToken成功,直接返回
        if (sessionAccessToken != null && (!sessionAccessToken.isExpired()
                || refreshToken(sessionAccessToken.getRefreshToken(), request))) {
            return true;
        }
        String code = request.getParameter(Oauth2Constant.AUTH_CODE);
        if (code != null) {
            // 获取accessToken
            getAccessToken(code, request);
            // 为去掉URL中授权码参数,再跳转一次当前地址
            redirectLocalRemoveCode(request, response);
        }
        else {
            redirectLogin(request, response);
        }
        return false;
    }

第一个if (sessionAccessToken != null && (!sessionAccessToken.isExpired() || refreshToken(sessionAccessToken.getRefreshToken(), request)))因为第一次登录跳转sessionAccessToken 为null

5、 所以进入if (code != null)方法体

if (code != null) {
 // 获取accessToken
    getAccessToken(code, request);
    // 为去掉URL中授权码参数,再跳转一次当前地址
    redirectLocalRemoveCode(request, response);
}

1.进去 getAccessToken(code, request);方法

private void getAccessToken(String code, HttpServletRequest request) {
        Result<RpcAccessToken> result = Oauth2Utils.getAccessToken(getServerUrl(), getAppId(),
                getAppSecret(), code);
        if (!result.isSuccess()) {
            logger.error("getAccessToken has error, message:{}", result.getMessage());
            return;
        }
        setAccessTokenInSession(result.getData(), request);
    }

1.带着临时授权码code调用http://authentication.sso.com:8080/oauth2/access_token去认证中心获取用户信息、并且消费code后删除code信息(临时授权码只能生效一次)
2. 调用 setAccessTokenInSession(result.getData(), request);把登录信息存储到session中,记录session与token的映射关系

private boolean setAccessTokenInSession(RpcAccessToken rpcAccessToken, HttpServletRequest request) {
        if (rpcAccessToken == null) {
            return false;
        }
        // 记录accessToken到本地session
        SessionUtils.setAccessToken(request, rpcAccessToken);

        // 记录本地session和accessToken映射
        recordSession(request, rpcAccessToken.getAccessToken());
        return true;
    }

6、最后调用 redirectLocalRemoveCode(request, response);去掉授权码信息带着登录成功信息再次请求http://client.sso.com:8082/

/**
     * 去除返回地址中的票据参数
     * @param request
     * @return
     * @throws IOException
     */
    private void redirectLocalRemoveCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String currentUrl = getCurrentUrl(request);
        currentUrl = currentUrl.substring(0, currentUrl.indexOf(Oauth2Constant.AUTH_CODE) - 1);
        response.sendRedirect(currentUrl);
    }

总结

单点登录,资源都在各个业务系统这边,不在SSO那一方。 用户在给SSO服务器提供了用户名密码后,作为业务系统并不知道这件事。 SSO随便给业务系统一个ST,那么业务系统是不能确定这个ST是用户伪造的,还是真的有效,所以要拿着这个ST去SSO服务器再问一下,这个用户给我的ST是否有效,是有效的我才能让这个用户访问
配套视频地址https://www.bilibili.com/video/BV1SR4y1P7XJ/

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-05 11:04:09  更:2022-05-05 11:08:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:22:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码