用户登录实现:
1.创建登录dto层(用于前端数据的接收,与前端值名一定要相同!!!)
2.创建service层方法
因为与注册一样basemapper没有注册的功能调用只有简单的增删改查,所以要创建对应的登录方法)而且由于登录和注册使用同一种数据库表所以不需要再进行创建数据表和创建对应实体类和basemapper
这边我们在用户的服务层上写入登录用到的两个方法
3.在编写方法的前先创建jwtutil(是一个生成webToken的工具类)
用用户名(email)生成唯一的token用来校验用户是否要进行重新登录
这个tonken生成后会发送回去给前端,之后客户端请求都会把这个token带回来,并每次带回来都会用服务器对它校验除了校验它是否正确还要对判断是否超期了
比如我这边是产生token时系统时间加上1000个小时超期
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)) //超期时间,对token进行超期判断(这边是现在系统时间+一千个小时)
就是说token错误或者token超期都会让用户重新登录。
(补充:
使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:
客户端使用用户名跟密码请求登录
服务端收到请求,去验证用户名与密码
验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据)
代码解释非常详细了
public static final long EXPIRATION_TIME = 3600_000_000L; // 1000 hour
public static final String SECRET = "ThisIsASecret"; //密钥加密
public static String generateToken(String userId) {
//生成map对象
HashMap<String, Object> map = new HashMap<>();
//把一个用户名(邮箱号)添加到map里
map.put(USER_NAME, userId);
//生成java web token (调用jwts包里面的方法,来生成token)
String jwt = Jwts.builder() //创建一个对象
.setClaims(map) //加密的数据传入map,传入userid就是用户邮箱
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)) //超期时间,对token进行超期判断
.signWith(SignatureAlgorithm.HS512, SECRET) //签名算法进行加密
.compact(); //压缩,成乱码字符串,之后再用相同密钥把map解密出来
return jwt; //jwt前面一般都会加Bearer
}
4.创建方法的实体类(在与上面注册下面接着写两个方法)
getUserByUsername(String username)方法:
注释很详细了,大致来说,该方法就是用接受到前端的email值返回出数据库中唯一一条相同email的记录(使用了basemapper里面的selectone方法)
@Override //通过email查到用户信息
public UserinFormationTable getUserByUsername(String username) {
//在数据库中找到一个与前端传过来email值相同的邮箱号用户对象(其中包含了加密的密码和邮箱)
return baseMapper.selectOne(new LambdaQueryWrapper<UserinFormationTable>().eq(UserinFormationTable::getMailbox, username));
}
executeLogin方法:
代码注释很详细
大致就是接受前端的dto数据调用getUserByUsername(String username)方法来读取对应email在数据库中的加密密码,与对dto数据进行相同加密后的密码进行比较,不相同或者没有注册都会则抛出失败,相同则生成一个token,并返回token,用于controller层的调用
@Override
public String executeLogin(LoginDTO dto) {
String token = null;
try {
//使用前面的getUserByUsername()方法,把在数据库找到的用户放入user中,用于调用
UserinFormationTable user = getUserByUsername(dto.getEmail());
String encodePwd = MD5Utils.getPwd(dto.getPassword());//对传过来的密码进行相同的加密,用于后面与数据库中的加密密码作比较
//如果encodePwd(前端传来的输入密码并进行相同加密后的值)和user.getPassword()(数据库中对应email的加密密码)不同则密码错误
if(!encodePwd.equals(user.getPassword()))
{
throw new Exception("密码错误");
}
//如果相同
token = JwtUtil.generateToken(String.valueOf(user.getMailbox()));//用邮箱用户名生成一个token
//token=user.getMailbox();
} catch (Exception e) {
log.warn("用户不存在or密码验证失败=======>{}", dto.getEmail());
}
return token;
}
5.登录controller层的实现
写在注册接口的下面
这样写数据会被返回在http://xxx//ums/user/login
代码注释很详细!
大致就是自动接收前端post请求返回的数据,调用executeLogin()方法如果token值为空,则说明executeLogin()方法中密码错误或者用户没有注册则返回失败,不为空则把token值返回给前端,并返回成功
@RequestMapping(value = "/login", method = RequestMethod.POST)
//自动接收到客户端发给我们的字段,dto里面的字段需要和前端的一模一样
public ApiResult<Map<String, String>> login(@Valid @RequestBody LoginDTO dto) {
String token = userinFormationtableService.executeLogin(dto);//调用service层中的executeLogin()传回token值
//如果token值为空,则说明executeLogin()方法中密码错误或者用户没有注册则返回失败
if (ObjectUtils.isEmpty(token)) {
return ApiResult.failed("flase");
}
//如果不为空则把token值返回给前端,并返回成功
Map<String, String> map = new HashMap<>(16);
map.put("token", token);
return ApiResult.success(map, "true");
}
最后用postman演示前端发送post请求
前提该用户已经注册