分布式项目中要实现单点登录(SSO - Single Sign On)
:对于同一个客户端(例如 Chrome 浏览器),只要登录了一个子站(例如 a.com
),则所有子站(b.com
、c.com
)都认为已经登录。
比如用户在登录淘宝后,跳转到天猫时就已经登录了。
通过redis
缓存和cookie
实现单点登录:
登录接口逻辑处理:
@ResponseBody
@RequestMapping("/dologin")
public Result<String> doLogin(String nickname,String password,HttpServletResponse response){
User loginUser = userDao.selectUserByNickName(nickname);
if(loginUser == null){
return Result.error(CodeMsg.NICKNAME_NOT_EXIST);
}
String salt = loginUser.getSalt();
//将表单提交的密码二次md5
String s = Md5Utils.formPassToDb(password, salt);
//验证密码
if(s.equals(loginUser.getPassword())){
//生成随机的token
String token = UUIDUtil.uuid();
//将token和用户作为key与value存入缓存
redisService.set(MiaoSha_UserKey.userKeyToken,token,loginUser);
//封装cookie
Cookie cookie = new Cookie(COOKIE_NAME,token);
//设置cookie过期时间
cookie.setMaxAge(MiaoSha_UserKey.userKeyToken.getExpireSeconds());
cookie.setPath("/");
response.addCookie(cookie);
return Result.success(token);
}
return Result.error(CodeMsg.SERVER_ERROR);
}
在其他接口中获取到登录用户,自定义一个参数解析器HandlerMethodArgumentResolver
在进行参数判断中可自定义一个注解,当某个参数被使用该注解后,则调用自定义的参数管理器
@Target(value = ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UserParameter {
}
HandlerMethodArgumentResolver
:
@Component
public class UserArgumentResolver implements HandlerMethodArgumentResolver {
@Autowired
private UserService userService;
//先判断参数类型和是否贴了自定义注解,满足则进行下一步
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType() == User.class && parameter.hasParameterAnnotation(UserParameter.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory){
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
Cookie[] cookies = request.getCookies();
if(cookies == null || cookies.length <=0){
return null;
}
String token = null;
for(Cookie cookie : cookies){
if(cookie.getName().equals(LoginController.COOKIE_NAME)){
//拿到token
token = cookie.getValue();
break;
}
}
User user = userService.getUserByToken(token);
return user;
}
}
遍历所有的cookie
,直到找到登录时设置的 public static final String COOKIE_NAME = "token";
获取该cookie
的值(token
)并查找redis
拿到用户
将自定义解析器配置到springmvc
管理:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private UserArgumentResolver userArgumentResolver;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(userArgumentResolver);
}
}