token令牌以及登录小例子

本文介绍了在前后端分离的场景下,如何利用Token令牌进行登录验证。首先,通过账号密码获取Token,然后在Controller层生成并返回Token。接着,使用拦截器验证请求头中的Token,确保用户已登录。此外,讨论了使用Redis存储Token以应对项目重启时的用户体验问题,避免用户频繁登录。
摘要由CSDN通过智能技术生成

token令牌:通过账号密码换取一个有时效的token令牌,基于token去进行认证和授权相关的操作。

在进行登录验证时,我们需要session或cookie会话进行验证,前端包括浏览器还有微信小程序、app、公众号,而采用前后端分离并且不使用浏览器的情况下就会导致前端无法用cookie存储信息,这时我们就需要使用token令牌进行登录验证。

使用token令牌前后端交互验证登录过程如下图:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAU3NobV82NjY=,size_20,color_FFFFFF,t_70,g_se,x_16

从上图可以看到和session验证时很相似的。

基于内存存储token令牌示例如下:

先在springboot项目中创建一个util包,再创建一个TokenUtil类:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAU3NobV82NjY=,size_17,color_FFFFFF,t_70,g_se,x_16

代码如下:

public class TokenUtil {
    /**
     * 创建map用于存储所有的令牌
     */
    private static Map<String, User> tokenMap=new HashMap<>();
    /**
     * 生成token,存储token-user对应关系
     * 返回token令牌
     */
    public static String generateToken(User user){
        String token = UUID.randomUUID().toString();
        tokenMap.put(token,user);
        return token;
    }

    /**
     * 验证token是否合法
     * @param token
     * @return
     */
    public static boolean verify(String token){
        return tokenMap.containsKey(token);
    }

    /**
     * 根据token获取用户信息
     * @param token
     * @return
     */
    public static User getUser(String token){
        return tokenMap.get(token);
    }
}

 在controller层中生成token令牌:

@RestController
@RequestMapping("user")
public class UserController {
    @Autowired
    private HttpSession session;
    @Autowired
    private UserService userService;
    @RequestMapping(value = "login",method = {RequestMethod.GET,RequestMethod.POST})
    public Map<String,Object> login(User user){
        Map<String,Object> map=new HashMap<>();
        if(StringUtils.isEmpty(user.getUsername())||StringUtil.isEmpty(user.getPassword())){
            map.put("code",0);
            map.put("msg","用户未输入账户或密码");

        }
        QueryWrapper<User> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("username",user.getUsername());
        queryWrapper.eq("password",user.getPassword());
        User one = userService.getOne(queryWrapper);
        if(one!=null){
            //生成token令牌
            String token = TokenUtil.generateToken(user);
            session.setAttribute("user",user.getUsername());
            map.put("date",one);
            map.put("code",1);
            map.put("token",token);
        }else{
            map.put("msg","用户名或密码错误");
        }
        return map;
    }

}

最后在拦截器中进行验证:

public class LoginInterceptor implements HandlerInterceptor {
    @Autowired
    private HttpSession httpSession;


    //Controller逻辑执行之前
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        String uri = request.getRequestURI();
        System.out.println(uri);


        /**
         * HandlerMethod=>Controller中标注@RequestMapping的方法
         *  需要配置静态资源不拦截时,添加这块逻辑  => 前后端分离项目
         */
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        //从header中获取token令牌信息
        String token = request.getHeader("token");
        //进行验证
        if (!TokenUtil.verify(token) &&httpSession.getAttribute("user") == null) {
            // 未登录跳转到登录界面
            response.sendRedirect("/user/toLogin");
            return false;
        } else {
            return true;
        }
    }

    //Controller逻辑执行完毕但是视图解析器还未进行解析之前
   @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    //Controller逻辑和视图解析器执行完毕
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }
}

 生成拦截器:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor()).addPathPatterns("/**")
                // 那些路径不拦截
                .excludePathPatterns("/user/login","/error","/swagger-ui.html/**","/swagger-resources/**");
    }

    @Bean
    public LoginInterceptor loginInterceptor(){
        return new LoginInterceptor();
    }
}

进行测试时需要在请求头中放入token令牌信息。

token和session都是有实效的。

在登录后,每次重新启动项目都要进行一次登录,如果用户多的情况就会使数据库过载,使用token令牌时还有一个作用就是我们可以使用Redis缓存中间件对token令牌信息进行存储,在重新启动项目时,不会对已经登录的用户造成影响,不需要进行再次登录,让用户有更好的体验。

如下图:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAU3NobV82NjY=,size_20,color_FFFFFF,t_70,g_se,x_16

 也可以使用mysql数据库存储令牌信息但是Redis读写效率比数据库高

 

 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sshm_666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值