SSO单点登录(四)客户端的设计与实现

目录

SSO单点登录(一)理论知识总结
SSO单点登录(二)基于redis的服务端
SSO单点登录(三)基于session的服务端
SSO单点登录(四)客户端的设计与实现
SSO单点登录(五)服务端集成dubbo版本
持续更新中…


1.概述

一直在写服务端做的事情,今天来看下客户端(目标子系统)是怎样对接的,我比较注重核心思想的表达,一些代码的细节,各位小伙伴自己补充,后面可以考虑编写一个完整的代码demo给大家,废话不多说,看下客户端怎样实现的

2.客户端设计要点

  • 子系统跳转
  • 校验token
  • 用户信息获取

3.核心代码设计

3.1 拦截器处理

/**
* 拦截器
* @author yanghao
* @version WebInterceptor.java, v 0.1 2019-06-21 09:43
*/
@Slf4j
@Component
public class WebInterceptor implements HandlerInterceptor {

    /**
    * SSO认证鉴权接口 ( 对应前面章节的applyAuth接口 )
    */
    private static final String SSO_AUTH_URL = ".../applyAuth";

    /**
    * 目前子系统首页(如果直接访问子系统,跳到sso登录页面,登录成功后直接跳转到此页面)
    */
    private static final String SYSTEM_INDEX_URL = "...";
    
    @Resource
    private RedisCache redisCache;
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //请求token
        String token = request.getHeader(AuthConstant.TOKEN);

        //用户信息
        LoginUserInfoCache userInfoCache;

        //判断局部会话
        HttpSession session = request.getSession(true);
        if(session.getAttribute(AuthConstant.SESSION_USER) == null){
            //请求统一认证中心校验token
            userInfoCache = applyAuth(request);
            //记录session
            session.setAttribute(AuthConstant.SESSION_USER, userInfoCache);

        }else{
            userInfoCache = (LoginUserInfoCache)session.getAttribute(AuthConstant.SESSION_USER);

            //目标系统直接登录时,校验token是否与当前一致
            if (!Objects.equals(token, userInfoCache.getToken())) {
                //请求统一认证中心校验token
                userInfoCache = applyAuth(request);
                //记录session
                session.setAttribute(AuthConstant.SESSION_USER, userInfoCache);
            }

        }

        // redis缓存存储用户信息(2小时有效期,可自定义)
        redisCache.put(StrUtil.format(CacheKeyConstant.LOGIN_USER_INFO_KEY, token), userInfoCache, 2 * 24 * 60 * 60);

        return true;

    }

    /**
     * 请求统一认证中心校验token
     * @param request
     * @return
     */
    private LoginUserInfoCache applyAuth(HttpServletRequest request) {
        //请求token
        String token = request.getHeader(AuthConstant.TOKEN);

        //用户信息(参考客户端章节里面到用户UserInfo定义)
        LoginUserInfoCache loginUserInfoCache;

        //请求认证中心参数
        Map<String, String> map = Maps.newHashMap();
        map.put("token", token);
        map.put("redirectUrl", SYSTEM_INDEX_URL);

        //AuthResult定义与服务端里面定义格式一样,参考前面章节
        AuthResult applyAuthResult = null;
        try {
            //http工具类,大家自己更换!!!
            String result = RequestUtil.post(SSO_AUTH_URL, JSON.toJSONString(map));
            applyAuthResult = JSON.parseObject(String.valueOf(JSON.parseObject(result, ApiResponse.class).getData()), ApplyAuthResult.class);

        }catch (Exception e){
            //请求过程中的异常统一处理(异常大家自己定义处理)
            log.error("请求统一认证中心校验token异常 >> applyAuth >> token = {}, error = {}", token, ExceptionUtils.getStackTrace(e));
            throw new AuthException(AuthEnum.TOKEN_AUTH_ERROR, "请求统一认证中心校验token异常");

        }

        if(applyAuthResult.isAuth()){
            loginUserInfoCache = BeanUtil.map(applyAuthResult, LoginUserInfoCache.class);
            return loginUserInfoCache;

        }else{
            //校验失败时跳转(返回参数里面的RedirectUrl给前端跳转) 异常大家自己处理,返回给前端固定标识,要跳转到到页面
            throw new AuthException(AuthEnum.TOKEN_AUTH_ERROR, applyAuthResult.getRedirectUrl());

        }

    }

}

4.总结

  • 客户端端核心思想就是首次跳转过来,我们需要将token参数传递过来,并且去检验token的有效性,这样做的目的是为了防止,有人直接去访问目标子系统的首页了,那这个时候一定需要校验token的有效性,防止有人恶意登录
  • 一旦session无用户信息,或者前后的token传过来不一致,都是需要重新去认证鉴权的
  • 一旦认证鉴权失败,需要将要跳转的页面传给前端(前后端分离,由前端跳转;如果前后端在一起,可以后端重定向)
  • 本文由作者原创,转载请表明出处https://blog.csdn.net/weixin_43968234/article/details/93168521
发布了39 篇原创文章 · 获赞 58 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43968234/article/details/93168521