cookie
注意:只有主域名相同,浏览器在访问时才会携带对应的 cookie
是由服务器发送给客户端(浏览器)的少量信息
作用
cookie是键值对形式存储的少量信息
我们知道,平时上网时都是使用无状态的HTTP协议传输出数据,这意味着客户端与服务端在数据传送完成后就会中断连接。这时我们就需要一个一直保持会话连接的机制。在session出现前,cookie就完全充当了这种角色。也就是,cookie的小量信息能帮助我们跟踪会话。一般该信息记录用户身份。
原理
客户端请求服务器时,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。而客户端浏览器会把Cookie保存起来。当浏览器再请求服务器时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器通过检查该Cookie来获取用户状态。
单点登录
单点登录三种实现方式
- session广播实现
即session复制,登录一个模块后,将信息存入session,复制session到其它模块中,复制会消耗资源,适合小型项目. - Redis+Cookie实现
在项目中的某个模块进行登录
将用户登录信息存入Redis,key随机生成(uuid),value: 用户信息(可以是登录凭证token,在从表中查询userId)
将Redis中生成的key存入cookie中
访问项目其它模块,发送请求带着cookie进行发送,获取cookie,从cookie中获取key值,到Redis中查询,如果查询到数据就登录 - token实现
在项目中某个模块进行登录,登陆后生成IWT字符串,把字符串返回
1、通过cookie返回
2、通过地址栏返回
当用户去访问其它模块时,每次访问都带着字符串,在访问模块中获取字符串,从字符串中获取用户信息,如果获取到就登录
如果想设置过期时间,可以设置Redis的过期时间
session默认过期时间30min
jwt组成:JWT头部、有效载荷、签名
1、用户注册
1、定义RegisterVo
@Data
@ApiModel(value="注册对象", description="注册对象")
public class RegisterVo {
@ApiModelProperty(value = "昵称")
private String nickname;
@ApiModelProperty(value = "手机号")
private String mobile;
@ApiModelProperty(value = "密码")
private String password;
// @ApiModelProperty(value = "验证码")
// private String code;
}
2、UcenterMemberController
//注册
@PostMapping("register")
public R Register(@RequestBody RegisterVo registerVo){
ucenterMemberService.register(registerVo);
return R.ok();
}
3、UcenterMemberServiceImpl
//注册
@Override
public void register(RegisterVo registerVo) {
//将数据加入到数据库中
String mobile = registerVo.getMobile(); //手机号
String nickname = registerVo.getNickname(); //昵称
String password = registerVo.getPassword(); //密码
if(StringUtils.isEmpty(mobile) || StringUtils.isEmpty(nickname) || StringUtils.isEmpty(password)){
throw new GuliException(20001, "注册失败");
}
//判断手机号是否有重复,重复的不进行注册
QueryWrapper<UcenterMember> wrapper = new QueryWrapper<>();
wrapper.eq("mobile", registerVo.getMobile());
Integer count = baseMapper.selectCount(wrapper);
if(count > 0){
//该手机号已经被注册过了
throw new GuliException(20001, "注册失败,该账号已被注册!");
}
//向数据库中添加数据
UcenterMember ucenterMember = new UcenterMember();
ucenterMember.setMobile(registerVo.getMobile());
//密码需要加密
ucenterMember.setPassword(MD5.encrypt(registerVo.getPassword()));
ucenterMember.setNickname(registerVo.getNickname());
//是否禁用
ucenterMember.setIsDisabled(false); //不被禁用
ucenterMember.setAvatar("https://online-teach-file.oss-cn-beijing.aliyuncs.com/cms/2019/11/14/297acd3b-b592-4cfb-a446-a28310369675.jpg");
baseMapper.insert(ucenterMember);
}
2、用户登录
1、UcenterMemberController
//登录,在数据库中查询用户名和密码
@PostMapping("login")
public R loginUser(@RequestBody UcenterMember member){
//调用service方法实现登录
String token = ucenterMemberService.login(member);
return R.ok().data("token", token);
}
2、UcenterMemberServiceImpl
@Override
public String login(UcenterMember member) {
String mobile = member.getMobile();
String password = member.getPassword();
if(StringUtils.isEmpty(mobile) || StringUtils.isEmpty(password)){
throw new GuliException(20001, "登录失败");
}
//判断手机号是否正确
QueryWrapper<UcenterMember> wrapper = new QueryWrapper<>();
wrapper.eq("mobile", mobile);
UcenterMember mobileMember = baseMapper.selectOne(wrapper);
//判断查出来的用户是否为空
if(mobileMember == null){
throw new GuliException(20001, "登录失败,账号有误!");
}
//判断密码,数据库存储的密码是密文,MD5加密后的
if(!MD5.encrypt(password).equals(mobileMember.getPassword())){
throw new GuliException(20001, "登录失败,密码错误!");
}
//判断用户是否禁用
if(mobileMember.getIsDisabled()){
throw new GuliException(20001, "登录失败,该用户已被禁用!");
}
//登录成功
//生成token字符串,使用jwt工具类
String token = JwtUtils.getJwtToken(mobileMember.getId(), mobileMember.getNickname());
return token;
}
3、生成jwt
//生成token字符串的方法
public static String getJwtToken(String id, String nickname){
String JwtToken = Jwts.builder()
.setHeaderParam("typ", "JWT")
.setHeaderParam("alg", "HS256")
.setSubject("guli-user")
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
.claim("id", id) //设置token主体部分 ,存储用户信息
.claim("nickname", nickname)
.signWith(SignatureAlgorithm.HS256, APP_SECRET)
.compact();
return JwtToken;
}
4、前端
login.js
//登录
submitLogin(userInfo) {
return request({
url: `/educenter/member/login`,
method: 'post',
data: userInfo
})
},
//根据token获取用户信息
getLoginInfo() {
return request({
url: `/educenter/member/getMemberInfo`,
method: 'get',
// headers: {'token': cookie.get('guli_token')}
})
//headers: {'token': cookie.get('guli_token')}
}
login.vue
data () {
return {
user:{
mobile:'',
password:''
},
//获取用户信息
loginInfo:{}
}
},
methods: {
submitLogin(){
loginApi.submitLogin(this.user).then(response => {
cookie.set('guli_token', response.data.data.token, {domain: 'localhost'})
//登录成功根据token获取用户信息
loginApi.getLoginInfo().then(response => {
this.loginInfo = JSON.stringify(response.data.data.userInfo)
//将用户信息记录cookie
cookie.set('guli_ucenter', this.loginInfo, { domain: 'localhost' })
//跳转页面
window.location.href = "/";
})
})
},
将jwt存入cookie中
5、根据jwt获取用户信息
UcenterMemberController
@ApiOperation(value = "根据token获取登录信息")
@GetMapping("getMemberInfo")
public R getLoginInfo(HttpServletRequest request){
try {
//调用jwt方法,request头信息
String memberId = JwtUtils.getMemberIdByJwtToken(request);
UcenterMember member = ucenterMemberService.getById(memberId);
System.out.println(member);
return R.ok().data("userInfo", member);
}catch (Exception e){
e.printStackTrace();
throw new GuliException(20001,"error");
}
}