问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

手撸SSO单点登录(四)登录验证-首次登录

发布网友 发布时间:2024-10-04 06:46

我来回答

1个回答

热心网友 时间:2024-10-27 16:40

一、目标

前一章节讲解了各应用未登录的系统统一跳转至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.TicketGrantingTicketManager的 sessionManager.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进去方法体代码中、此方法体作用如下:

生成一个管理端的登录凭证TGT

把凭证与用户信息存储内存Map(TGT,用户信息)

把凭证等信息放入Cookie中

3、调用com.yuantai.controller.BaseLoginController的generateCodeAndRedirect(redirectUri, tgt)方法

String?generateCodeAndRedirect(String?redirectUri,?String?tgt)?throws?UnsupportedEncodingException?{????????//?生成授权码????????String?code?=?codeManager.generate(tgt,?true,?redirectUri);????????return?"redirect:"?+?authRedirectUri(redirectUri,?code);????}

生成临时授权码code,并把code与codeContent内容存入map(code,content内存)

后台发起重定向请求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/

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
小孩子的谜语有哪些? 高频UPS不间断电源厂家有推荐的吗? 农历 女:1986-10-16 属虎,男 1985-02-11 属牛,想在2013 年结婚,请问... ...12月21日出生属牛,女阴历1986年10月20日出生属虎,请问2012上半年哪天... 男属牛农历1985年正月16日生日,女属虎1986年10月26日生日,今年九月份左 ... ...属牛 女方:1986年农历10月20日 属虎 11年4月或5月结婚有合适的日子吗... 凌云诺怎么查看技能信息 凌云诺如何查看技能信息 凌云诺查看品阶福利的操作方法 凌云诺怎么查看品阶福利 凌云诺怎么查看本周个人活跃度 凌云诺查看本周个人活跃度的方法_百度... 深圳宝安正规医院割痔疮要多少钱 ...也可理解为5与2两数在数轴上所对应的两点之间的距离; 可以看做... ...也可理解为5与2两数在数轴上所对应的两点之间的距离;|5+2|可以... ...也可以理解为5与2两数在数轴上所对应的两点之间的距离 ...实际上也可理解为5与-2两数在数轴上所对应的两点之间的 ...实际上也可理解为5和-2两数在数轴上所对的两点 请告知三句半与诗歌朗诵的分别?朗涌诗歌会给听成三句半呜??? “氢弹之父”于敏和氢弹原理突破的百日会战 | 赛先生 进攻3秒是什么意思? 3秒违例规则定义 汗蒸销售朋友圈话术怎么说 汗蒸销售技巧和方法 亿万股民为什么如此深恶痛绝股指期货 10平方米的电线有多粗 急!找一篇热爱祖国、歌颂祖国或者歌颂党的诗歌,朗诵演出用最好有配乐... 一辆汽车三分之二小时行驶18千米,一小时行多少千米?行一千米需要多少小... ...分之2,第二次用去这根绳子的3分之2,第三次用去2米,还剩多少?_百度知... 十八的三分之二与几米的五分之一样长a6b15c60d30 —块长方形田地,长18米,宽是长的3分之2,它的面积是多少?用综合... 一根18米长的绳子按3:2分成两段较长的一段占全长的几分之几较短的一段... 一块长方体地,宽18米,是长的3分之2,这块地的面积多少? (加分)华诞60周年 经典诗文朗诵比赛 参赛作品求助 晚上睡觉的时候我会磨牙,我没有去看过医生 4s店氢氧除碳有必要吗 支付定金签了合同违约金应该怎么处理 售房合同叫订金后毁约怎么处理 亨利·劳伦斯·甘特的主要著作 亨利·劳伦斯·甘特的奖励工资制 上海拍写真或艺术照那边属于中高档次的? 亨利·劳伦斯·甘特人际关系理论 为什么冰箱内的照明灯会一闪一闪的 为什么冰箱内的照明灯会一闪一闪的... 瑞金革命纪念馆历史沿革 夏季鼻子突然留血如何应急? 耳朵流黄色的水在晚上,有没有应急办法让它不流? 瑞金革命遗址及纪念馆基本概况 瑞金革命遗址及纪念馆关于瑞金 喝山楂水能降血压吗 瑞金革命遗址维护 瑞金革命遗址及纪念馆历史记录 卡西欧DT930数据采集器 C语言编程问题 如何在扫描条码成功的情况下调... 卡西欧DT930卡机怎么办 网络脱口秀节目有哪些