登录生成token详细流程

 token的作用

在登录的过程中为什么要有token的存在呢?

在登录功能中使用 token 的主要目的是为了实现用户身份验证和授权管理。使用 token 可以帮助系统实现以下功能:

  1. 身份验证: 用户在登录成功后会收到一个包含 token 的响应。之后,用户每次请求需要在请求头中携带该 token,服务端可以根据 token 来验证用户的身份和权限。

  2. 状态管理: 通过 token 可以实现状态无关性,即服务端不需要存储用户的登录状态。每次请求都携带 token,服务端可以根据 token 来识别用户身份,而不需要在服务端存储用户的登录状态。

  3. 安全性: 使用 token 可以增加系统的安全性。通过合适的算法和密钥进行 token 签名,可以防止 token 被伪造,从而保护用户数据的安全。

  4. 权限管理: 通过 token 可以实现对用户访问权限的管理。在 token 中可以包含用户的角色信息或者权限信息,服务端可以根据 token 中的信息来判断用户是否有权限进行特定操作。

  5. 跨平台支持: token 可以在不同的客户端和服务端间进行传递,因此支持跨平台的登录验证。

综上所述,使用 token 可以简化系统的状态管理,增强安全性,实现权限管理,并支持跨平台的用户验证,是一种常见且有效的用户认证和授权方式。

登录流程图

那么,在整个过程中,生辰token的具体流程是怎样的呢:流程图奉上

登录生成token详细流程_第1张图片

这个流程图看起来比较复杂,实际上只有生成token的规则和生成token之后的对其进行的处理两步操作,实现起来会非常简单。

该功能实现应用到的技术:springBoot + mybatis-plus + redis 

1. 登录生成token详细流程_第2张图片

当我们在登录页面输入完成用户名和密码后,在用户名和密码都正确的情况下,发出请求

 后端代码实现

controller层:

@RestController
@RequestMapping("/login")
@CrossOrigin
public class LoginController{

    @Autowired
    private UserService userService;    
    /**
     * 登录
     * user
     *
     * @param
     * @return
     */
    @GetMapping(value = "/getUserInfo")
    public ResponseEntity> getUserInfo (String userCode,String password){
        return userService.getUserInfo(userCode,password);
    }

}


serviceImpl:

@Service
public class UserServiceImpl extends ServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserRoleJoinMapper join;
    @Resource
    private RedisTemplate redisTemplate;
    @Autowired
    private JavaMailSender mailSender;


    /**
     * 登录验证功能
     * @param userCode
     * @param password
     * @return
     */

    //ResponseEntity Spring框架的Web应用程序中常见的返回响应的方式
    @Override
    public ResponseEntity> getUserInfo(String userCode, String password) {
        Map response = new HashMap<>();
        MPJLambdaWrapper wrapper = new MPJLambdaWrapper<>();
        wrapper.select(User::getUserId,User::getUserCode,User::getUserName,User::getPassword,User::getRoleId,User::getRegistrationTime,
                User::getEmail)
                .selectAs(Role::getRoleId,UserRoleJoin::getRoleId)
                .leftJoin(Role.class,Role::getRoleId,User::getRoleId);

        wrapper.eq("userCode",userCode);


        User user = join.selectOne(wrapper);
        //判断用户是否存在
        if (null != user){
            //用户存在,判断密码是否正确
            if (password.equals(user.getPassword())) {
                // 生成Token
                String token = generateToken(userCode);
                //将token存入redies中
                Map userMap = new HashMap();
                userMap.put("userName",user.getUserName());
                userMap.put("passWord",user.getPassword());
                userMap.put("email",user.getEmail());
                userMap.put("roleId",user.getRoleId().toString());
                userMap.put("userId",user.getUserId().toString());
                userMap.put("registrationTime",user.getRegistrationTime().toString());
                redisTemplate.opsForValue().set("token:"+token,userMap);
                response.put("token",token);

                return ResponseEntity.ok(response);
            }else {
                //返回一个HTTP 401状态码的响应 表示未经授权响应的ResponseEntity实例,并将其作为HTTP响应返回给客户端
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
            }
        }else {
            response.put("msg","用户不存在");
            //返回一个HTTP 401状态码的响应 表示未经授权响应的ResponseEntity实例,并将其作为HTTP响应返回给客户端
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
        }
    }

}

/**
 * 生成token的规则:
 * 生成随机的字符串
 * 年月日时分秒+用户编码
 * @param userCode
 * @return
 */
private String generateToken(String userCode) {

    //定义token
    String token = "";
    //获取日期和时间
    LocalDateTime now = LocalDateTime.now();
    // 拼接年月日时分秒("%02d" 转换为两位数的字符串)
    String dataTimeString = now.getYear() + String.format("%02d", now.getMonthValue()) +
            String.format("%02d", now.getDayOfMonth()) + String.format("%02d", now.getHour()) +
            String.format("%02d", now.getMinute()) + String.format("%02d", now.getSecond());
    Random random = new Random();
    //随机生成5位数
    int randomNumber = random.nextInt(90000) + 10000;
    String randomNum = Integer.toString(randomNumber);
    //拼接token
    token = token + dataTimeString + userCode + randomNum;
    return token;
}

 实现类实现了生成token的具体流程,目前没有使用md5编码格式加密,方便存入redis中便于查看

登录生成token详细流程_第3张图片

 保存到redis中的格式: 将用户信息存入到以生成的token作为key的redis键值对中

注意:redis可视化工具使用了    RedisDesktopManager , 如果需要可在下方留言,我会做一期教程给大家

mapper接口: 

@Mapper
public interface UserMapper extends BaseMapper {

}

以上为代码实现的流程,包括流程图中对于token的生成以及在redis中的操作

前端处理

2.那么前端该如何处理呢,使用的前端技术是 vue+element-ui

登录生成token详细流程_第4张图片

这段代码对服务端返回的token进行了处理,将token保存到了localStaorage中 

登录生成token详细流程_第5张图片

可以使用F12进入调试模式,找到应用程序,可以在local storage 中找到存储的token 

3. 为什么本地要存到local storage中呢,那能不能存到cookie中呢?

Cookie和LocalStorage的区别

Cookie和LocalStorage是Web开发中常用的客户端存储技术,它们有以下区别和作用:

  1. 存储容量:

    • Cookie:每个域名下的Cookie总大小通常限制为4KB左右。

    • LocalStorage:每个域名下的LocalStorage总大小通常限制为5MB或更大(具体取决于浏览器)。

  2. 生命周期:

    • Cookie:可以设置过期时间,使得数据在有效期内保持,也可以设置为会话Cookie,关闭浏览器后自动删除。

    • LocalStorage:除非被主动删除,否则数据会一直保存在浏览器中。

  3. 数据发送:

    • Cookie:每次请求都会将Cookie数据发送到服务器,增加网络传输量。

    • LocalStorage:数据不会自动发送到服务器,仅在客户端使用。

  4. 安全性:

    • Cookie:可以设置Secure标志以限制只在HTTPS连接中传输,但Cookie信息容易被窃取或篡改。

    • LocalStorage:仅在客户端使用,不会随请求发送到服务器,更安全。

  5. 使用方式:

    • Cookie:可以通过JavaScript的document.cookie进行读写操作。

    • LocalStorage:可以通过JavaScript的localStorage对象进行读写操作。

作用方面:

  • Cookie主要用于在客户端和服务器之间存储会话信息、身份验证、跟踪用户行为等。

  • LocalStorage主要用于本地存储用户的持久化数据,例如用户首选项、表单数据等。

综上所述,Cookie适合用于需要在客户端和服务器之间交互的场景,而LocalStorage适用于需要在客户端长期保存数据的场景

结论:local storage 和 cookie都可以使用,取决于客户端和服务端之间交互的使用场景

你可能感兴趣的:(前端,java,spring,boot)