登录业务介绍(两种模式)
1.1 早期单一服务器,用户认证。
缺点:单点性能压力,无法扩展
1.2 分布式,SSO(single sign on)模式
好处 :
用户身份信息独立管理,更好的分布式管理。
可以自己扩展安全策略
跨域不是问题
(跨域:ip,port 不相同! Jsonp={得到其他域的信息}!@CrossOrigin, httpClient )
缺点:
认证服务器访问压力较大。
一、 单点登录业务
搭建认证中心模块
- 修改pom.xml
- application.properties
server.port=8087
spring.thymeleaf.cache=false
spring.thymeleaf.mode=LEGACYHTML5
spring.dubbo.application.name=passport-web
spring.dubbo.registry.protocol=zookeeper
spring.dubbo.registry.address=192.168.67.202:2181
spring.dubbo.base-package=com.atguigu.gmall
spring.dubbo.protocol.name=dubbo
spring.dubbo.consumer.timeout=100000
spring.dubbo.consumer.check=false
3.导入静态资源和登录页面
4.建立controller控制器,测试页面
登录功能
1 思路:
1、 用接收的用户名密码核对后台数据库
2、 将用户信息加载到写入redis,redis中有该用户视为登录状态。
3、 用userId+当前用户登录ip地址+密钥生成token
4、 重定向用户到之前的来源地址,同时把token作为参数附上。
2 实现类核对后台登录信息+用户登录信息载入缓存
public String userKey_prefix="user:";
public String userinfoKey_suffix=":info";
public int userKey_timeOut=60*60*24;
@Override
public UserInfo login(UserInfo userInfo) {
String password = DigestUtils.md5DigestAsHex(userInfo.getPasswd().getBytes());
userInfo.setPasswd(password);
UserInfo info = userInfoMapper.selectOne(userInfo);
if (info!=null){
Jedis jedis=null;
try {
jedis = redisUtil.getJedis();
jedis.setex(userKey_prefix+userInfo.getId()+userinfoKey_suffix,userKey_timeOut, JSON.toJSONString(info));
return info;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedis!=null){
jedis.close();
}
}
}
return null;
}
在application.properties 配置文件中要添加
在启动类的时候,不要忘记加,扫描RedisUtils 工具类(@ComponentScan(“com.atguigu.gmall”))
spring.redis.host=192.168.xx.xxx
spring.redis.port=6379
spring.redis.database=0
3 生成token
3.1JWT工具
JWT(Json Web Token)的原理,
一个JWT由三个部分组成:公共部分、私有部分、签名部分。最后由这三者组合进行base64编码得到JWT。
JWT 最重要的作用就是对 token信息的防伪作用。
3.2使用配置
pom依赖 放到gmall-web-util中
Jwt工具类
测试下
3.3代码实现
配置nginx / host
upstream passport.atguigu.com{
server 192.168.xx.xxx:8087;
}
server {
listen 80;
server_name passport.atguigu.com;
location / {
proxy_pass http://passport.atguigu.com;
proxy_set_header X-forwarded-for $proxy_add_x_forwarded_for;
}
}
控制器
@Value("${token.key}")
String signKey;
@RequestMapping("login")
@ResponseBody
public String login(HttpServletRequest request, UserInfo userInfo){
// 取得ip地址
String remoteAddr = request.getHeader("X-forwarded-for");
if (userInfo!=null) {
UserInfo loginUser = userInfoService.login(userInfo);
if (loginUser == null) {
return "fail";
} else {
// 生成token
Map map = new HashMap();
map.put("userId", loginUser.getId());
map.put("nickName", loginUser.getNickName());
String token = JwtUtil.encode(signKey, map, remoteAddr);
return token;
}
}
return "fail";
}
4 验证功能
功能:当业务模块某个页面要检查当前用户是否登录时,提交到认证中心,认证中心进行检查校验,返回登录状态、用户Id和用户名称。
4.1 思路:
1、 利用密钥和IP检验token是否正确,并获得里面的userId
Map<String, Object> map = JwtUtil.decode(token, signKey, currentIp);
2、 用userId检查Redis中是否有用户信息,如果有延长它的过期时间。
String key=userKey_prefix+userId+userinfoKey_suffix;
String userJson = jedis.get(key);
...
jedis.expire(key,userKey_timeOut);
3、 登录成功状态返回。
if(userInfo!=null){
return "success";
}
return "fail";
二、 业务模块页面登录情况检查
-
将登录之后的token 放入cookie 中
-
使用拦截器来获取token!{token 中已经有用户的昵称}
-
系统中哪些模块需要用户登录 {在需要登录的控制器上添加一个注解} 自定义注解