1. 单点登录
所在位置:
1.1 单点登录业务介绍
早期单一服务器,用户认证。
缺点:单点性能压力,无法扩展
分布式,SSO(single sign on)模式
解决 :
用户身份信息独立管理,更好的分布式管理。
可以自己扩展安全策略
跨域不是问题
缺点:
认证服务器访问压力较大。
业务流程图{用户访问业务时,必须登录的流程}{单点登录的过程}
2. 认证中心模块
2.1 实现思路
1、用接收的用户名密码核对后台数据库
2、核对通过,用uuid生成token
3、将用户id加载到写入redis,redis的key为token,value为用户id。
4、登录成功返回token与用户信息,将token与用户信息记录到cookie里面 重定向用户到之前的来源地址。
数据库表:user_info,并添加一条数据!密码应该是加密的!
2.2 认证中心模块业务代码
实体类:
@Data
@ApiModel(description = "userInfo")
@TableName("user_info")
public class UserInfo extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "用户名称")
@TableField("login_name")
private String loginName;
@ApiModelProperty(value = "用户昵称")
@TableField("nick_name")
private String nickName;
@ApiModelProperty(value = "用户密码")
@TableField("passwd")
private String passwd;
@ApiModelProperty(value = "用户姓名")
@TableField("name")
private String name;
@ApiModelProperty(value = "手机号")
@TableField("phone_num")
private String phoneNum;
@ApiModelProperty(value = "邮箱")
@TableField("email")
private String email;
@ApiModelProperty(value = "头像")
@TableField("head_img")
private String headImg;
@ApiModelProperty(value = "用户级别")
@TableField("user_level")
private String userLevel;
}
mapper:
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}
接口:
public interface UserService {
/**
* 登录方法
* @param userInfo
* @return
*/
UserInfo login(UserInfo userInfo);
}
实现:
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserInfoMapper userInfoMapper;
@Override
public UserInfo login(UserInfo userInfo) {
//注意密码是加密的
String passwd = userInfo.getPasswd();
String newPasswd = DigestUtils.md5DigestAsHex(passwd.getBytes());
//构建构造器查询
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper();
queryWrapper.eq("login_name", userInfo.getLoginName());
queryWrapper.eq("passwd", newPasswd);
UserInfo userInfo1 = userInfoMapper.selectOne(queryWrapper);
if (userInfo1 != null) {
return userInfo1;
}
return null;
}
}
控制器:
@RestController
@RequestMapping("/api/user/passport")
public class UserInfoController {
@Autowired
UserService userService;
@Autowired
RedisTemplate redisTemplate;
/**
* @description: 登录
* @author MIS
* @date: 2022/10/17 12:05
* @Param: userInfo
* @Param: request
* @Param: response
* @Return: com.atguigu.gmall.common.result.Result
*/
@PostMapping("login")
public Result login(@RequestBody UserInfo userInfo, HttpServletRequest request, HttpServletResponse response) {
UserInfo info = userService.login(userInfo);
//密码账号匹配成功
if (info != null) {
//用UUid构造token作为存入缓存的key
String token = UUID.randomUUID().toString().replaceAll("-", "");
//存储用户信息作为存入缓存的value
JSONObject userJson = new JSONObject();
userJson.put("userId", info.getId().toString());
//同时存入ip作为验证是否同一个ip防止伪造token增加安全性
userJson.put("ip", IpUtil.getIpAddress(request));
//存入redis中
redisTemplate.opsForValue().set(RedisConst.USER_LOGIN_KEY_PREFIX + token, userJson.toJSONString(), RedisConst.USERKEY_TIMEOUT, TimeUnit.SECONDS);
Object o = redisTemplate.opsForValue().get(RedisConst.USER_LOGIN_KEY_PREFIX + token);
System.out.println(RedisConst.USER_LOGIN_KEY_PREFIX + token+"==================="+o.toString());
//返回数据给前端 存入cookie
HashMap<String, Object> map = new HashMap<>();
map.put("nickName", info.getNickName());
map.put("token", token);
return Result.ok(map);
} else {
return Result.fail().message("用户名或密码错误");
}
}
/**
* 退出登录
* @param request
* @return
*/
@GetMapping("logout")
public Result logout(HttpServletRequest request){
//从请求头中获取token, 然后从缓存中删除
redisTemplate.delete(RedisConst.USER_LOGIN_KEY_PREFIX + request.getHeader("token"));
return Result.ok();
}
}