目录
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