SpringBoot+vue+token

前端
token验证
1、前端接受后台发过来的token,将其存入sessionStorage,并且在store.js中进行存储

 state: {
    // 存储token
    Authorization: sessionStorage.getItem('Authorization') ? sessionStorage.getItem('Authorization') : ''
  },
  mutations: {
    // 修改token,并将token存入localStorage
    changeLogin (state, user) {
      state.Authorization = user.Authorization;
      sessionStorage.setItem('Authorization', user.Authorization);
    },
    logout(state) {
      sessionStorage.removeItem('Authorization');
      sessionStorage.removeItem('user');

      state.token = null
    }
  },

2、路由守卫:将没有登录信息的访问请求全部转到login.vue,有相关信息则放行

router.beforeEach((to, from, next) => { // 路由跳转前监控(保证登录状态)
  // 重登陆删除本地数据
  if (to.path === '/login') {
    sessionStorage.removeItem('user')
  }
  let user = JSON.parse(sessionStorage.getItem('user'))
  // 登录验证:如果本地没有储存用户且不在登录页面则跳转
  if (!user && to.path !== '/login') {
    next({ path: '/login' })
  } else {
    next()
  }
})

3、配置请求头:这里使用axios,所以在axios的配置文件中添加:

axios.interceptors.request.use(
    config => {
      if (localStorage.getItem('Authorization')) {
        config.headers.Authorization = sessionStorage.getItem('Authorization');
      }
   
      return config;
    },
    error => {
      return Promise.reject(error);
    });

//http response 拦截器
axios.interceptors.response.use(
  response => {
      return response;
  },
  error => {
      if (error.response) {
          console.log(this);
          Vue.$store.commit("logout");
          Vue.$router.push({ path: "/login" });
      }
      return Promise.reject(error.response.data)
});

后端
token验证(集成jwt)
在pom.xml文件中导入相关依赖

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

生成token

@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.getUid().toString()).withIssuedAt(start).withExpiresAt(end)
                .sign(Algorithm.HMAC256(user.getPassword()));
        return token;
    }
}

添加两个相关注解

//用来跳过验证的PassToken
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {
    boolean required() default true;
}

//需要登录才能进行操作的注解UserLoginToken
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {
    boolean required() default true;
}

添加一个拦截器判断访问该controller是否需要验证token

public class tokenInterceptor implements HandlerInterceptor {
        @Autowired
        UserService userService;

    /**
     *          预处理回调,判断每个处理器是否符合要求,返回true表示符合要求,放行
     *          这里主要是对user的id和password进行解密,如果要改变,还需要改变生成token的service
     * @param httpServletRequest
     * @param httpServletResponse
     * @param object
     *          拦截的对象
     * @return
     * @throws Exception
     */
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
            String token = httpServletRequest.getHeader("Authorization");// 从 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) {
                        //jwt解码失败
                        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");
                    }
                    //将验证通过后的用户信息放到请求中
                    httpServletRequest.setAttribute("currentUser", user);
                    return true;
                }
            }
            return true;
        }

    /**
     *         处理器执行之后,视图解析器渲染之前 执行的回调
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     *         处理器执行后返回的数据
     * @param modelAndView
     * @throws Exception
     */
        @Override
        public void postHandle(HttpServletRequest httpServletRequest,
                               HttpServletResponse httpServletResponse,
                               Object o, ModelAndView modelAndView) throws Exception {

        }

    /**
     *          视图解析器将视图解析之后的回调
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     * @param e
     * @throws Exception
     */
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest,
                                    HttpServletResponse httpServletResponse,
                                    Object o, Exception e) throws Exception {
        }

}

jwt的配置类

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
   @Override
   public void addInterceptors(InterceptorRegistry registry) {
       registry.addInterceptor(authenticationInterceptor())
               .addPathPatterns("/**");    // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
   }
   @Bean
   public tokenInterceptor authenticationInterceptor() {
       return new tokenInterceptor();
   }
}	

使用
在controller中需要进行token验证的方法中添加@UserLoginToken

--------------------------------------分隔符
vue手动刷新页面,axios拦截器不执行情况

  1. 需求: vue里面的拦截器在每次请求前添加上token(Authorization)
  2. 问题:正常点击请求可以添加,一旦手动F5刷新页面,就直接没有进入拦截器,再次发送请求就恢复
  3. 分析原因: 需要把axios放外面单独封装,不放mian.js里面即可

src下面新建文件夹utils,文件名称intercept.js


import axios from 'axios'

axios.defaults.withCredentials = true
export const request = (config) => {
  return axios(config)
}

// 请求前设置header
axios.interceptors.request.use(
  config => {
    if (localStorage.getItem('Authorization')) {
      config.headers.Authorization = localStorage.getItem('Authorization')
    }

    return config
  },
  error => {
    return Promise.reject(error)
  })
// 请求完成后 拦截器
axios.interceptors.response.use(
  response => {
    console.log(response)
    if (response.data.code === 1003) {
      router.replace({
        path: '/login'
      })
      localStorage.removeItem('Authorization')
    }
    return response
  },
  error => {
    if (error.response) {
      switch (error.response.status) {
        case 401:
          localStorage.removeItem('Authorization')
          router.replace({
            path: '/login',
            query: {redirect: router.currentRoute.fullPath} // 登录成功后 跳转当前页面
          })
      }
    }
  }
)
// 这句一定要写
export default axios


然后在main.js引入,这里要注意import引入顺序,否则可能导致其他有问题。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 Spring Boot 和 Vue.js 实现 token 验证的步骤如下: 1. 在 Spring Boot 后端实现 token 的生成和验证逻辑。 创建一个 TokenUtil 类,用于生成和验证 token。可以使用 Java JWT(jjwt)库来简化操作。 ```java import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.security.Keys; import org.springframework.stereotype.Component; import javax.crypto.SecretKey; import java.util.Date; @Component public class TokenUtil { private static final String SECRET_KEY = "your_secret_key_here"; private static final long EXPIRATION_TIME = 86400000; // 过期时间设置为一天 // 生成 token public String generateToken(String userId) { SecretKey key = Keys.hmacShaKeyFor(SECRET_KEY.getBytes()); return Jwts.builder() .setSubject(userId) .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)) .signWith(key) .compact(); } // 验证 token public boolean validateToken(String token) { try { SecretKey key = Keys.hmacShaKeyFor(SECRET_KEY.getBytes()); Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token); return true; } catch (Exception e) { return false; } } // 获取 token 中的用户ID public String getUserIdFromToken(String token) { SecretKey key = Keys.hmacShaKeyFor(SECRET_KEY.getBytes()); Claims claims = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody(); return claims.getSubject(); } } ``` 2. 在 Spring Boot 的控制器中添加 token 相关的接口。 创建一个 UserController 类,用于处理用户相关的请求。 ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api") public class UserController { @Autowired private TokenUtil tokenUtil; @PostMapping("/login") public String login(@RequestBody User user) { // 验证用户登录逻辑,验证通过后生成 token if (authenticate(user.getUsername(), user.getPassword())) { String token = tokenUtil.generateToken(user.getUsername()); return token; } else { return "Invalid credentials"; } } @GetMapping("/user") public String getUserInfo(@RequestHeader("Authorization") String token) { // 验证 token 的有效性,并返回用户信息 if (tokenUtil.validateToken(token)) { String userId = tokenUtil.getUserIdFromToken(token); // 根据 userId 获取用户信息并返回 return "User: " + userId; } else { return "Invalid token"; } } private boolean authenticate(String username, String password) { // 用户登录验证逻辑 // 返回 true 表示验证通过,返回 false 表示验证失败 // 这里只做演示,实际情况需要根据实际业务逻辑进行验证 return username.equals("admin") && password.equals("password"); } } ``` 3. 在 Vue.js 前端发送登录请求,并使用获取到的 token 发送其他请求。 使用 axios 发送登录请求,并将获取到的 token 存储到浏览器的 localStorage 中。 ```javascript import axios from 'axios' const login = (username, password) => { return axios.post('/api/login', { username, password }) .then(response => { const token = response.data localStorage.setItem('token', token) }) } ``` 在其他需要验证身份的请求中,将存储的 token 添加到请求的头部 Authorization 中。 ```javascript import axios from 'axios' const getUserInfo = () => { const token = localStorage.getItem('token') const config = { headers: { 'Authorization': token } } return axios.get('/api/user', config) .then(response => { const userInfo = response.data return userInfo }) } ``` 这样,在发送请求时,后端会验证传递的 token 的有效性,并根据需要执行相应的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值