token登录的实现

token登录的实现

我这种token只是简单的实现token,就是后端利用UUID 生成简单随机码,利用随机码作为在Redis中的键,然后存储的用户信息作为值,在每次合理请求的时候对token的有效时间进行刷新(利用拦截器),以确保用户信息的有效性。

为什么要用token

使用令牌(Token)进行身份验证和授权是一种常见的方式,特别适用于分布式和跨域请求的应用程序。

1. 为什么要使用 Token:

  • 无状态性:Token 身份验证是无状态的,不需要在服务器端存储会话信息。每个请求都包含了身份信息,因此服务器不需要维护状态。
  • 跨域支持:Token 可以轻松处理跨域请求,因为令牌可以在 HTTP 请求的头部(通常是 Authorization 头部)中传递,而不受同源策略的限制。
  • 扩展性:Token 可以包含任意信息,因此可以用于传递用户权限、角色、过期时间等信息。

2. Token 使用逻辑:

  • 用户登录成功后,生成一个 Token 并将用户信息存储在服务器端(如 Redis)以便快速验证和获取用户信息。
  • 向前端返回 Token。
  • 前端将 Token 存储在本地(通常是 sessionStorage 或 localStorage)。
  • 在每个后续的请求中,前端将 Token 通过请求头(通常是 Authorization 头)发送给后端。
  • 后端从请求头中获取 Token,验证其合法性,并使用 Token 获取用户信息。

后端(Spring Boot)示例:

定义login接口

java 复制代码
@GetMapping("/login")
    public BaseResponse<String> login(String username,String password){
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getUsername,username);
        User one = userService.getOne(lambdaQueryWrapper);
        if(one == null){
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForHash().putAll("test:user:"+token, BeanUtil.beanToMap(one));
        redisTemplate.expire("test:user:" + token,2, TimeUnit.MINUTES);
        return ResultUtils.success(token);
    }

定义一个获取用户信息的其他接口

java 复制代码
@GetMapping("/get")
    public BaseResponse<User> get(){
        return ResultUtils.success(UserHolder.getValue());
    }

创建拦截器:

java 复制代码
public class LoginInterceptor implements HandlerInterceptor {
    private RedisTemplate<String,Object> redisTemplate;
    public LoginInterceptor(RedisTemplate<String,Object> template){
        this.redisTemplate = template;
    }
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // 获取 session
        String token = request.getHeader("Authorization");
                // 检查用户是否已登录
        User user = new User();
        BeanUtil.fillBeanWithMap(redisTemplate.opsForHash().entries("test:user:"+token),user,false);
        if(user == null|| BeanUtil.isEmpty(user)){
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        redisTemplate.expire("test:user:"+token,2, TimeUnit.MINUTES);
        // 将用户数据存储到 ThreadLocal 中,以便在整个请求周期内访问
        UserHolder.setValue(user);
        // 进行其他逻辑验证,根据需求自行添加
        return true; // 允许请求继续执行
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        // 在请求处理之后执行,可以对 ModelAndView 进行修改
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // 在请求完成之后执行,用于资源清理等操作

        // 清理 ThreadLocal 中的用户数据,防止内存泄漏
        UserHolder.clear();
    }

注册拦截器:

java 复制代码
@Configuration
public class MvcConfig implements WebMvcConfigurer {
    @Resource
    private RedisTemplate<String,Object> redisTemplate;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 登录拦截器
        registry.addInterceptor(new LoginInterceptor(redisTemplate))
                .addPathPatterns("/**").excludePathPatterns("/user/login");
    }
}

使用结果截图

结果返回了一个token,这个token前端拿到以后要保存到sessionStorage或者LocalStorage里面,再把这个token送到请求头中,就可以啦

另一个请求:

设置请求头

设置Authorization

然后发起就可以得到啦

如果没有authorization就是得到未登录结果

前端(Vue.js)示例:

vue 复制代码
<!-- Login.vue -->
<template>
  <div>
    <input v-model="username" placeholder="Username" />
    <input type="password" v-model="password" placeholder="Password" />
    <button @click="login">Login</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      username: '',
      password: ''
    };
  },
  methods: {
    login() {
      // 发送登录请求,获取 Token
      axios.post('/api/user/login', { username: this.username, password: this.password })
        .then(response => {
          const token = response.data.token;
          // 存储 Token 到 sessionStorage
          sessionStorage.setItem('token', token);
          // 跳转到其他页面或进行其他操作
        })
        .catch(error => {
          console.error('Login failed:', error);
        });
    }
  }
};
</script>
相关推荐
影子落人间几秒前
已解决npm ERR! request to https://registry.npm.taobao.org/@vant%2farea-data failed
前端·npm·node.js
骆晨学长14 分钟前
基于springboot的智慧社区微信小程序
java·数据库·spring boot·后端·微信小程序·小程序
AskHarries19 分钟前
利用反射实现动态代理
java·后端·reflect
@月落20 分钟前
alibaba获得店铺的所有商品 API接口
java·大数据·数据库·人工智能·学习
世俗ˊ25 分钟前
CSS入门笔记
前端·css·笔记
liuyang-neu25 分钟前
力扣 42.接雨水
java·算法·leetcode
子非鱼92125 分钟前
【前端】ES6:Set与Map
前端·javascript·es6
z千鑫29 分钟前
【人工智能】如何利用AI轻松将java,c++等代码转换为Python语言?程序员必读
java·c++·人工智能·gpt·agent·ai编程·ai工具
6230_30 分钟前
git使用“保姆级”教程1——简介及配置项设置
前端·git·学习·html·web3·学习方法·改行学it
想退休的搬砖人39 分钟前
vue选项式写法项目案例(购物车)
前端·javascript·vue.js