Java实现Token登录验证(基于JWT的token认证实现)

news2025/2/27 21:01:13

文章目录

  • 一、JWT是什么?
  • 二、使用步骤
    • 1.项目结构
    • 2.相关依赖
    • 3.数据库
    • 4.相关代码
  • 三、测试结果

一、JWT是什么?

在介绍JWT之前,我们先来回顾一下利用token进行用户身份验证的流程:

1、客户端使用用户名和密码请求登录

2、服务端收到请求,验证用户名和密码

3、验证成功后,服务端会签发一个token,再把这个token返回给客户端

4、客户端收到token后可以把它存储起来,比如放到cookie中

5、客户端每次向服务端请求资源时需要携带服务端签发的token,可以在cookie或者header中携带

6、服务端收到请求,然后去验证客户端请求里面带着的token,如果验证成功,就向客户端返回请求数据

这种基于token的认证方式相比传统的session认证方式更节约服务器资源,并且对移动端和分布式更加友好。其优点如下

支持跨域访问:cookie是无法跨域的,而token由于没有用到cookie(前提是将token放到请求头中),所以跨域后不会存在信息丢失问题
无状态:token机制在服务端不需要存储session信息,因为token自身包含了所有登录用户的信息,所以可以减轻服务端压力
更适用CDN:可以通过内容分发网络请求服务端的所有资料
更适用于移动端:当客户端是非浏览器平台时,cookie是不被支持的,此时采用token认证方式会简单很多
无需考虑CSRF:由于不再依赖cookie,所以采用token认证方式不会发生CSRF,所以也就无需考虑CSRF的防御

而JWT就是上述流程当中token的一种具体实现方式,其全称是JSON Web Token,官网地址:https://jwt.io/

通俗地说,JWT的本质就是一个字符串,它是将用户信息保存到一个Json字符串中,然后进行编码后得到一个JWT token,并且这个JWT token带有签名信息,接收后可以校验是否被篡改,所以可以用于在各方之间安全地将信息作为Json对象传输。JWT的认证流程如下:

1、首先,前端通过Web表单将自己的用户名和密码发送到后端的接口,这个过程一般是一个POST请求。建议的方式是通过SSL加密的传输(HTTPS),从而避免敏感信息被嗅探

2、后端核对用户名和密码成功后,将包含用户信息的数据作为JWT的Payload,将其与JWT Header分别进行Base64编码拼接后签名,形成一个JWT Token,形成的JWT Token就是一个如同lll.zzz.xxx的字符串
3、后端将JWT Token字符串作为登录成功的结果返回给前端。前端可以将返回的结果保存在浏览器中,退出登录时删除保存的JWT Token即可

4、前端在每次请求时将JWT Token放入HTTP请求头中的Authorization属性中(解决XSS和XSRF问题)

5、后端检查前端传过来的JWT Token,验证其有效性,比如检查签名是否正确、是否过期、token的接收方是否是自己等等

6、验证通过后,后端解析出JWT Token中包含的用户信息,进行其他逻辑操作(一般是根据用户信息得到权限等),返回结果
在这里插入图片描述

最后:说白了,JWT:JSON Web Token,其实token就是一段字符串,由三部分组成:Header,Payload,Signature

二、使用步骤

1.项目结构

在这里插入图片描述

2.相关依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.22</version>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.21</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3.2</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.79</version>
        </dependency>

        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.4</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.11.0</version>
        </dependency>

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.2</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.3.8.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.18.3</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
    </dependencies>

3.数据库

这里进行测试,所以用户类只有用户名密码,自行创建
在这里插入图片描述

4.相关代码

1、annotation包
PassToken:

package com.geesun.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author :Mr.ZJW
 * @date :Created 2022/2/28 10:26
 * @description:用来跳过验证的 PassToken
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {
    boolean required() default true;
}

UserLoginToken:

package com.geesun.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author :Mr.ZJW
 * @date :Created 2022/2/28 10:26
 * @description:用于登录后才能操作的token
 */
/*RetentionPolicy.RUNTIME:这种类型的Annotations将被JVM保留,
所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用。*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {
    boolean required() default true;
}

2、common包
CodeMsg:

package com.geesun.common;

/**
 * @author :Mr.ZJW
 * @date :Created 2022/2/28 10:26
 * @description:返回提示
 */
public class CodeMsg {
    private int retCode;
    private String message;
    // 按照模块定义CodeMsg
    // 通用异常
    public static CodeMsg SUCCESS = new CodeMsg(0,"success");
    public static CodeMsg SERVER_EXCEPTION = new CodeMsg(500100,"服务端异常");
    public static CodeMsg PARAMETER_ISNULL = new CodeMsg(500101,"输入参数为空");
    // 业务异常
    public static CodeMsg USER_NOT_EXSIST = new CodeMsg(500102,"用户不存在");
    public static CodeMsg ONLINE_USER_OVER = new CodeMsg(500103,"在线用户数超出允许登录的最大用户限制。");
    public static CodeMsg SESSION_NOT_EXSIST =  new CodeMsg(500104,"不存在离线session数据");
    public static CodeMsg NOT_FIND_DATA = new CodeMsg(500105,"查找不到对应数据");
    public static CodeMsg USER_OR_PASS_ERROR = new CodeMsg(500102,"账号或者密码错误,请重试!");


    private CodeMsg(int retCode, String message) {
        this.retCode = retCode;
        this.message = message;
    }

    public int getRetCode() {
        return retCode;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
}

Result:

package com.geesun.common;

/**
 * @author :Mr.ZJW
 * @date :Created 2022/2/28 10:26
 * @description:返回统一结果集
 */
public class Result<T> {

    private String message;
    private int retCode;
    private T data;

    private Result(T data) {
        this.retCode = 200;
        this.message = "成功";
        this.data = data;
    }

    private Result(CodeMsg cm) {
        if(cm == null){
            return;
        }
        this.retCode = cm.getRetCode();
        this.message = cm.getMessage();
    }

    /**
     * 成功时候的调用
     * @return
     */
    public static <T> Result<T> success(T data){
        return new Result<T>(data);
    }

    /**
     * 成功,不需要传入参数
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> Result<T> success(){
        return (Result<T>) success("");
    }
    /**
     * 失败时候的调用
     * @return
     */
    public static <T> Result<T> error(CodeMsg cm){
        return new Result<T>(cm);
    }
    /**
     * 失败时候的调用,扩展消息参数
     * @param cm
     * @param msg
     * @return
     */
    public static <T> Result<T> error(CodeMsg cm,String msg){
        cm.setMessage(cm.getMessage()+"--"+msg);
        return new Result<T>(cm);
    }
    public T getData() {
        return data;
    }
    public String getMessage() {
        return message;
    }
    public int getRetCode() {
        return retCode;
    }
}

3、config包
InterceptorConfig:

package com.geesun.config;

import com.geesun.Interceptor.AuthenticationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.*;
import java.util.List;

/**
 * @author :Mr.ZJW
 * @date :Created 2022/2/28 10:25
 * @description:新建Token拦截器
 */
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authenticationInterceptor())
                .addPathPatterns("/**");    // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
    }
    @Bean
    public AuthenticationInterceptor authenticationInterceptor() {
        return new AuthenticationInterceptor();
    }
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> arg0) {
        // TODO Auto-generated method stub

    }
    @Override
    public void addCorsMappings(CorsRegistry arg0) {
        // TODO Auto-generated method stub

    }
    @Override
    public void addFormatters(FormatterRegistry arg0) {
        // TODO Auto-generated method stub

    }
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry arg0) {
        // TODO Auto-generated method stub

    }
    @Override
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> arg0) {
        // TODO Auto-generated method stub

    }
    @Override
    public void addViewControllers(ViewControllerRegistry arg0) {
        // TODO Auto-generated method stub

    }
    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer arg0) {
        // TODO Auto-generated method stub

    }
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer arg0) {
        // TODO Auto-generated method stub

    }
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer arg0) {
        // TODO Auto-generated method stub

    }
    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> arg0) {
        // TODO Auto-generated method stub

    }
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> arg0) {
        // TODO Auto-generated method stub

    }
    @Override
    public void configurePathMatch(PathMatchConfigurer arg0) {
        // TODO Auto-generated method stub

    }
    @Override
    public void configureViewResolvers(ViewResolverRegistry arg0) {
        // TODO Auto-generated method stub

    }
    @Override
    public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> arg0) {
        // TODO Auto-generated method stub

    }
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> arg0) {
        // TODO Auto-generated method stub

    }
    @Override
    public MessageCodesResolver getMessageCodesResolver() {
        // TODO Auto-generated method stub
        return null;
    }
    @Override
    public Validator getValidator() {
        // TODO Auto-generated method stub
        return null;
    }

}

4、Interceptor包
AuthenticationInterceptor:

package com.geesun.Interceptor;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.geesun.annotation.PassToken;
import com.geesun.annotation.UserLoginToken;
import com.geesun.pojo.User;
import com.geesun.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * @author :Mr.ZJW
 * @date :Created 2022/2/28 10:24
 * @description:拦截器
 */
public class AuthenticationInterceptor implements HandlerInterceptor {

    @Autowired
    UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
        String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token
        // 如果不是映射到方法直接通过
        if(!(object instanceof HandlerMethod)){
            return true;
        }
        HandlerMethod handlerMethod=(HandlerMethod)object;
        Method method=handlerMethod.getMethod();
        //检查是否有passtoken注释,有则跳过认证
        if (method.isAnnotationPresent(PassToken.class)) {
            PassToken passToken = method.getAnnotation(PassToken.class);
            if (passToken.required()) {
                return true;
            }
        }
        //检查有没有需要用户权限的注解
        if (method.isAnnotationPresent(UserLoginToken.class)) {
            UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
            if (userLoginToken.required()) {
                // 执行认证
                if (token == null) {
                    throw new RuntimeException("无token,请重新登录");
                }
                // 获取 token 中的 user id
                String userId;
                try {
                    userId = JWT.decode(token).getAudience().get(0);
                } catch (JWTDecodeException j) {
                    throw new RuntimeException("401");
                }
                User user = userService.findUserById(userId);
                if (user == null) {
                    throw new RuntimeException("用户不存在,请重新登录");
                }
                // 验证 token
                JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
                try {
                    jwtVerifier.verify(token);
                } catch (JWTVerificationException e) {
                    throw new RuntimeException("401");
                }
                return true;
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }
}

5、utils包
TokenUtil:

package com.geesun.utils;

import com.auth0.jwt.JWT;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;

/**
 * @author :Mr.ZJW
 * @date :Created 2022/2/28 10:24
 * @description:
 */
public class TokenUtil {

    public static String getTokenUserId() {
        String token = getRequest().getHeader("token");// 从 http 请求头中取出 token
        String userId = JWT.decode(token).getAudience().get(0);
        return userId;
    }

    /**
     * 获取request
     * @return
     */
    public static HttpServletRequest getRequest() {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        return requestAttributes == null ? null : requestAttributes.getRequest();
    }

}

6、pojo包
User:

package com.geesun.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "`user`")
public class User implements Serializable {
    @TableId(value = "id", type = IdType.NONE)
    private String id;

    @TableField(value = "username")
    private String username;

    @TableField(value = "password")
    private String password;

    private static final long serialVersionUID = 1L;
}

7、controller包
UserController:

package com.geesun.controller;

import cn.hutool.json.JSONObject;
import com.geesun.annotation.UserLoginToken;
import com.geesun.common.CodeMsg;
import com.geesun.common.Result;
import com.geesun.pojo.User;
import com.geesun.service.UserService;
import com.geesun.service.impl.TokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;

/**
 * @author :Mr.ZJW
 * @date :Created 2022/2/26 10:47
 * @description:
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @Autowired
    private TokenService tokenService;

    /**
     * 查询用户信息
     * @return
     */
    @UserLoginToken
    @GetMapping("/list")
    public Result<Object> list(){
        return Result.success(userService.list());
    }


    /**
     * 登录验证
     * @param user
     * @param response
     * @return
     */
    @RequestMapping(value = "/login" ,method = RequestMethod.GET)
    public Result<Object> login(User user, HttpServletResponse response) {
        JSONObject jsonObject = new JSONObject();
        //获取用户账号密码
        User userForBase = new User();
        userForBase.setId(userService.findByUsername(user).getId());
        userForBase.setUsername(userService.findByUsername(user).getUsername());
        userForBase.setPassword(userService.findByUsername(user).getPassword());
        //判断账号或密码是否正确
        if (!userForBase.getPassword().equals(user.getPassword())) {
            return Result.error(CodeMsg.USER_OR_PASS_ERROR);
        } else {
            String token = tokenService.getToken(userForBase);
            jsonObject.put("token", token);
            Cookie cookie = new Cookie("token", token);
            cookie.setPath("/");
            response.addCookie(cookie);
            return Result.success(jsonObject);
        }
    }
    
}

8、service包
UserService接口:

package com.geesun.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.geesun.pojo.User;

public interface UserService extends IService<User> {


    int deleteByIds(Long[] ids);

    int addUser(User user);

    User findByUsername(User user);

    User findUserById(String userId);
}

UserServiceImpl实现类:

package com.geesun.service.impl;

import cn.hutool.core.util.ArrayUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.geesun.mapper.UserMapper;
import com.geesun.pojo.User;
import com.geesun.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;
    
    /**
     * 判断用户名
     * @param user
     * @return
     */
    public User findByUsername(User user){
        return userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername,user.getUsername()));
    }

    public User findUserById(String userId) {
        return userMapper.selectById(userId);
    }

}

TokenService:

package com.geesun.service.impl;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.geesun.pojo.User;
import org.springframework.stereotype.Service;
import java.util.Date;

/**
 * @author :Mr.ZJW
 * @date :Created 2022/2/28 10:20
 * @description:
 */
@Service
public class TokenService {

    public String getToken(User user) {
        Date start = new Date();
        long currentTime = System.currentTimeMillis() + 60* 60 * 1000;//一小时有效时间
        Date end = new Date(currentTime);
        String token = "";

        token = JWT.create().withAudience(user.getId()).withIssuedAt(start).withExpiresAt(end)
                .sign(Algorithm.HMAC256(user.getPassword()));
        return token;
    }
}

9、mapper包

package com.geesun.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.geesun.pojo.User;

public interface UserMapper extends BaseMapper<User> {

}

三、测试结果

1、登录验证
在这里插入图片描述
2、查询用户信息
这个方法加上了@UserLoginToken,所以要token才能查询
在这里插入图片描述

在这里插入图片描述
3、不加上Token进行测试就会出错提示
在这里插入图片描述
出错提示:
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/405149.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【微信小程序】view和scroll-view组件的基本使用

✅作者简介&#xff1a;CSDN内容合伙人、阿里云专家博主、51CTO专家博主&#x1f3c6; &#x1f4c3;个人主页&#xff1a;hacker707的csdn博客 &#x1f525;系列专栏&#xff1a;微信小程序 &#x1f4ac;个人格言&#xff1a;但行好事&#xff0c;莫问前程 view和scroll-vie…

移动端适配详解 , 给你解决适配烦恼

试想一下&#xff0c;如果我们只能开发web端&#xff0c;那么移动端的网友由谁来做&#xff01;那也太悲惨了 所以&#xff0c;这里说的就是如何开发页面到移动端&#xff0c;适配各个手机型号&#xff0c;让页面在手机上跑起来&#xff5e; 目录 理解些许概念 1. 开发的种…

Vue3新特性——Composition API详解

文章目录一、 Vue3快速入门1. Vue3 带来了什么2. Vue3工程的创建2.1 使用vue-cli创建2.2 使用vite创建2.2.1 是什么2.2.2 vite的优势2.2.3 使用步骤3. vue3项目结构的分析3.1 vue-cli 项目结构4. vue3中的开发者工具4.1 在线安装4.2 离线安装二、常用Composition API1. setup2.…

Vue3获取DOM、操作组件

文章目录&#x1f31f; 写在前面&#x1f31f; Vue2 ref 的使用&#x1f31f; Vue3获取DOM&#x1f31f; Vue3操作组件&#x1f31f; 写在最后&#x1f31f; 写在前面 专栏介绍&#xff1a; 凉哥作为 Vue 的忠实 粉丝输出过大量的 Vue 文章&#xff0c;应粉丝要求开始更新 Vue…

若依框架前端Vue项目分析实战

说明 前面讲解了vue2的单点知识&#xff0c;下面用若依提供的vue项目&#xff0c;实战分析一下&#xff0c;拿到一个vue项目&#xff0c;如何进行分析并进行二次开发。 一、public/index.html与main.js和App.vue三者的关系 vue项目是单界面应用&#xff0c;所有的界面将在pu…

VSCode 入门操作大全 + 实用插件推荐【零基础专属详细教程】

&#x1f4c0; 前言&#xff1a; &#x1f3ab; 选择一个好的开发工具很重要&#xff0c;很多刚学编程的小伙伴在 webstorm 和 vscode 上很难抉择&#xff0c;我个人更喜欢使用 vscode&#xff0c;因为其有着简洁的操作风格和丰富的人性化的各种功能&#xff0c;这篇文章带给大…

2022年前端Vue常见面试题大全(三万长文)持续更新...

目录 1.Vue和React有什么不同&#xff1f;使用场景分别是什么&#xff1f; 2.axios是什么&#xff1f;怎么使用它&#xff0c;怎么解决跨域&#xff1f; 3.说说Vue&#xff0c;React&#xff0c;angularjs&#xff0c;jquery的区别 4.什么阶段&#xff08;生命周期&#xff…

2022最新版40个前端练手项目【附视频+源码】

不管学习哪门语言都希望能做出实际的东西来&#xff0c;这个实际的东西当然就是项目啦&#xff0c; 不用多 说&#xff0c;大家都知道学编程语言一定要做项目才行。 本次给到大家的是40个前端实战练手项目(附源码和视频讲解)&#xff0c;希望对大家有一定的帮助&#xff0c;激…

企微获取用户敏感数据

1、企微配置可信域名 2、企微获取成员userID 3、企微获取用户敏感数据 文章目录一、简介1、企微数据安全更新2、身份验证方式2.1 网页授权登录(企微内部)2.2 扫描授权登录(浏览器)二、企微应用配置1、企微配置可信域名2、企微授权登录3、企微可信IP三、网页授权登录方式(企微)1…

Vue2 大型项目升级 Vue3 详细经验总结

前言 前段时间&#xff0c;公司准备在现有的 Vue2 项目中做一个聊天系统&#xff0c;但考虑开发聊天系统的周期并不短&#xff0c;客户又急需。于是准备对接腾讯的 IM 组件&#xff0c;来实现。 不知道的这里贴个官网&#xff1a; IM TUIKit 官方文档 对于 TUIKit&#xff0…

【axios】axios的基本使用

axios是一个专注于网络请求的库。 不同于jquery&#xff0c;功能复杂&#xff0c;既可以操作dom&#xff0c;又可以做动画&#xff0c;还可以发ajax请求。axios是一个专注于网络请求的库。 一、基本使用 1.导入库文件 在js中导入axios的库文件后&#xff0c;会直接在全局挂载…

[vue 进阶] 关于dicts字典的用法

最近在学习若依系统的框架&#xff0c;其中发现一个很奇怪的事情&#xff0c;网上查询很多地方&#xff0c;也是一知半解。 网上搜索的结果如下&#xff0c;大家可以先看看&#xff1a; [vue 进阶] 关于dicts字典的用法_小钿钿不忘初心_的博客-CSDN博客前言在使用若依框架开发…

CSS3如何调整背景图片大小

系列文章目录 CSS3实现半透明边框&#xff08;1&#xff09; CSS3实现多重边框&#xff08;2&#xff09; CSS3如何改变背景图片大小系列文章目录一、background-size语法格式二、参数详解1.length2.percentage3.cover4.contain总结在CSS3中&#xff0c;如果想要调整背景图片的…

适合普通大学生的前端开发学习路线

大家好&#xff0c;我是帅地。 假如你没有明确的目标&#xff0c;或许可以按照我说的学习路线来学习一波&#xff0c;我写的每一份学习路线&#xff0c;不会很全面&#xff0c;因为我认为&#xff0c;东西列的太多&#xff0c;反而不利于新手的学习&#xff0c;所以我列举的&a…

Vue中的路由

目录 目录 一&#xff0c;路由理解 二&#xff0c;基本配置 第一步: 在main.js文件中引入并使用插件 第二步: 在src文件夹下创建一个router文件夹然后在文件夹下创建index.js ​编辑 第三步: 回到main.js中引入创建的 router 并在vue实例对象中使用 三&#xff0c;路由的…

vue使用富文本编辑器vue-quill-editor

问题描述&#xff1a; 我们在开发过程中经常会遇到使用富文本编辑器进行操作&#xff0c;当前插件市场上关于富文本的编辑器挺多的&#xff0c;我们就不一一个介绍了&#xff0c;现在我们主要讲解一些vue-quill-editor富文本编辑器的使用操作和注意事项。 效果图 具体操作使用…

是什么让学习 Web 开发在未来几年变得有价值?

&#x1f482; 个人网站:【海拥】【摸鱼游戏】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 想寻找共同学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】&#x1f30a; 本文首发…

React中ref的使用方法和使用场景(详解)

摘要 不管在Vue中还是React&#xff0c;如果我们想使用一个元素的DOM&#xff0c;不需要通过JS中操纵DOM的方法&#xff0c;它们提供了一个专属的API就是ref。 而Vue中的ref可能比较简单&#xff0c;这一篇主要讲一下如何在React中使用ref&#xff0c;以及使用ref的场景。 1…

如何创建vue3项目

目录 如何创建vue3项目 1、用vue cli创建 2、使用vite直接创建 3、使用vue3官方推荐创建方式 如何创建vue3项目 创建vue3我们常用的有三种方式&#xff1a; 1、用vue cli创建 1.使用vue cli环境前提条件&#xff1a; node -vv16.13.0 npm -v8.1.0 vue -Vvue/cli 4.5.15 …

微信小程序中使用vant组件库(超详细)

目录前言Vant Weapp的安装与使用1、安装 node.js2、通过 npm 安装3、修改 app.json4、修改 project.config.json5、构建 npm 包6、使用组件全局引入和局部引入全局引入局部引入Toast 组件的使用官方文档 API 详解Props 参数Events 事件Slot 插槽外部样式类前言 Vant是一个轻量…