1.需要实现的功能
①用户在任意模块进行登陆操作后,在系统中其它模块能查询到当前登陆用户的信息
②用户在登陆过一次系统后,应该记忆用户的用户名,下次不必登陆就可以在页面显示用户名,但是实际状态是未登录,且有过期时间
③用户在任意页面的登录按钮,登录后能回到原来的页面.
2.实现的思路
登陆服务单独创建一个用户登陆认证中心模块(分布式,SSO(single sign on)模式
对于第一条:①用户在任意模块进行登陆操作后,在系统中其它模块能查询到当前登陆用户的信息
这个是单点登录的最基本的功能,可以将用户登陆后的信息放在redis缓存中,每次用户登陆就设到缓存中,采用redis的str数据类型.key可以为user:{userId}:info,value可以设置为用户信息的json字符串.
服务中登陆的方法:
//key的前缀
public final String userKey_prefix = "user:";
//key的后缀
public final String userinfoKey_suffix=":info";
//过期时间 一个小时
public final int userKey_timeOut=60*60;
public UserInfo login(UserInfo userInfo) {
//密码的加密 DigestUtils是加密的工具类
userInfo.setPasswd(DigestUtils.md5DigestAsHex(userInfo.getPasswd().getBytes()));
//从数据库中查找用户是否存在
UserInfo loginUserInfo = userInfoMapper.selectOne(userInfo);
if(loginUserInfo!=null){
//redisUtil也是操作redis的工具类
Jedis jedis = redisUtil.getJedis();
String key = userKey_prefix+loginUserInfo.getId()+userinfoKey_suffix;
//保存到redis中
jedis.setex(key, userKey_timeOut, JSON.toJSONString(LoginUserInfo));
jedis.close();
}
return loginUserInfo;
}
当其他模块需要用户的登录信息时,就可以根据用户的userId直接去redis中查找.
//根据userId进行登陆认证
public UserInfo verify(String userId){
//去缓存中查询是否有对应userId的用户信息
Jedis jedis = redisUtil.getJedis();
//拼接key值前缀+userId+后缀
String key = userKey_prefix+userId+userinfoKey_suffix;
String userInfoJson = jedis.get(key);
if(userInfoJson!=null&&userInfoJson.trim().length()>0){
//给这个key重新设置失效时间
jedis.expire(key, userKey_timeOut);
UserInfo userInfo = JSON.parseObject(userInfoJson, UserInfo.class);
return userInfo;
}
return null;
}
对于第二三条:
②用户在登陆过一次系统后,应该记忆用户的用户名,下次不必登陆就可以在页面显示用户名,但是实际状态是未登录,且有过期时间.
③用户在任意页面的登录按钮,登录后能回到原来的页面.
这两个需求需要利用浏览器的cookie功能或者localStorage本地存储功能.这里只说利用cookie来实现.并利用一个简单的token机制
具体做法为:
- 用userId+当前用户登录ip地址+密钥生成token
- 重定向用户到之前的来源地址,同时把token作为参数附上。
- 将token设置到用户的浏览器cookie中,并设置一个过期时间,通过解密token就可以实现第二个需求
首先页面的所有登陆入口应该用js代码来控制,每次点击登陆按钮登陆时,应该带上一个originUrl的参数,用于保存登陆后需要跳转的页面控制器,一般设置为当前页面
function login(){
//使用encodeURIComponent()函数对url进行编码
var s = encodeURIComponent("http://xxx.xxx.com/cartList");
window.location