前后端分离:最基础的SpringBoot+JWT实现登陆认证(附完整项目GitHub地址)

JWT官网地址:https://jwt.io/

1. SpringBoot-JWT Demo结构

2. 数据库准备

只需要一张user表,用于保存用户的用户名和密码。

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, '张三', '123123');

SET FOREIGN_KEY_CHECKS = 1;

3. 代码实现

3.1 导入依赖

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

3.2 写生成token的方法

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.smallpineapple.springbootjwt.entity.User;

import java.util.Date;

/**
 * @author Zeng
 * @date 2020/2/17 10:56
 */
public class TokenUtil {
    //设置过期时间为1个小时
    private static final Long EXPIRE_TIME = Long.valueOf(1*60*60*1000);

    public static String getToken(User user){
        String token="";
        Date date = new Date();
        date.setTime(System.currentTimeMillis() + EXPIRE_TIME);
        token= JWT.create().withAudience(String.valueOf(user.getId())) //存入需要保存在token里的信息,这里把用户的id存入token中
                .withExpiresAt(date)//设置token的过期时间为1小时
                .sign(Algorithm.HMAC256(user.getPassword()));//使用HMAC256生成token,密钥是用户的密码
        return token;
    }

}

3.3 写拦截器对指定路径进行token验证

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.smallpineapple.springbootjwt.entity.User;
import com.smallpineapple.springbootjwt.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author Zeng
 * @date 2020/2/17 11:00
 */
public class TokenInterceptor implements HandlerInterceptor {

    @Autowired
    UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //从请求头中获取token
        String token = request.getHeader("token");
        //执行认证
        if(token == null){
            throw new RuntimeException("尚未登陆!");
        }
        //获取token中的userId
        String userId;
        try {
            //从解密的token中获取userId
            userId = JWT.decode(token).getAudience().get(0);
        } catch (JWTDecodeException j) {
            throw new RuntimeException("token异常!请重新登陆");
        }
        User user = userService.findUserById(Long.valueOf(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("token异常!请重新登陆");
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

3.4 配置拦截规则

import com.smallpineapple.springbootjwt.interceptor.TokenInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author Zeng
 * @date 2020/2/17 11:18
 */
@Configuration
public class WebMvcConfiguer implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(getTokenInterceptor())
                .addPathPatterns("/admin/**"); //访问以/admin/为前缀的所有路径都需要对token进行验证
    }

    @Bean
    public TokenInterceptor getTokenInterceptor(){
        return new TokenInterceptor();
    }

}

3.5 写接口并使用Postman测试

import com.smallpineapple.springbootjwt.entity.User;
import com.smallpineapple.springbootjwt.service.UserService;
import com.smallpineapple.springbootjwt.util.ResultUtil;
import com.smallpineapple.springbootjwt.util.TokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Zeng
 * @date 2020/2/16 22:24
 */
@RestController
public class UserController {

    @Autowired
    UserService userService;

    @PostMapping("/login")
    public ResultUtil login(String username, String password){
        User dbUser = userService.findUserByUsernameAndPassword(username, password);
        if (dbUser == null) {
            return ResultUtil.failure().addObject("err", "用户名或密码错误!");
        }
        //获取token
        String token = TokenUtil.getToken(dbUser);
        //返回给客户端保存
        return ResultUtil.success().addObject("token", token).addObject("user",dbUser);
    }

    @GetMapping("/admin/test")
    public ResultUtil testMethod(){
        return ResultUtil.success();
    }

}

未登录时尝试访问test接口被拒绝访问

用户登陆获取token

登陆后携带token访问test接口

token失效后尝试携带访问test接口被拒绝

完整项目GitHub地址:https://github.com/SmallPineApp1e/springboot-jwt


时间有限,能力有限,如果有任何错误务必指出!

发布了50 篇原创文章 · 获赞 46 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_41949328/article/details/104370935