【springboot】jwt实现token验证

什么是jwt

Json web token (JWT),用于进行身份验证,开销小,适用于单点登录。优点是token是以json加密的形式保存在客户端的,跨语言;能将用户需要的所有信息都加密到token里,不用多次查询数据库;不用在服务端保存会话信息,适用于分布式微服务。

  1. 用户使用账密发送post请求
  2. 服务器使用私钥创建jwt(生成签名)
  3. 服务器返回这个jwt给浏览器
  4. 浏览器将该jwt加在之后所有请求的请求头中
  5. 服务器拦截请求验证jwt(校验token)
  6. 验证通过则返回响应信息给浏览器

jwt构成:

  1. 头部(header):token类型和采用的加密算法
  2. 载荷(payload):存放有效信息:标准中注册的声明、公共的声明、私有的声明
  3. 签证(signature):签证信息:base64加密后的headerbase64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密
    https://jwt.io/#debugger-io

Debugger工具:https://jwt.io/#debugger-io

springboot集成jwt

依赖

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

自定义注解 @JwtToken

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface JwtToken {
    boolean required() default  true;
}

工具类,token的生成与校验

@Component
public class JwtUtil {
    /**
     * 静态方法调用非静态接口层(Service层)
     */
    public static JwtUtil jwtUtil; //声明对象

    @PostConstruct //初始化
    public void init() {
        jwtUtil = this;
        jwtUtil.userService = this.userService;
    }

    @Autowired //注入
            UserService userService;


    /**
     * 过期时间30分钟
     */
    private static final long EXPIRE_TIME = 30 * 60 * 1000;//自定义修改
    /**
     * jwt 密钥
     */
    private static final String SECRET = "abcde";//自定义修改

    /**
     * 生成签名,30分钟后过期
     *
     * @param userId
     * @return
     */
    public static String sign(String userId, String username) {
        try {
            //过期时间
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            //私钥及加密算法
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            //附带username和userID生成签名,可自定义附带信息,这里是用户ID和用户名称
            return JWT.create()
                    // 将 user id 保存到 token 里面
                    .withClaim("userId", userId)
                    .withClaim("username", username)
                    // 分钟后token过期
                    .withExpiresAt(date)
                    // token 的密钥
                    .sign(algorithm);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 校验token
     *
     * @param token
     * @return
     */
    public static boolean checkSign(String token) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            JWTVerifier verifier = JWT.require(algorithm)
                    .build();
            // 验证token
            DecodedJWT jwt = verifier.verify(token);
//            String subject = jwt.getSubject();
//            List<String> audience = jwt.getAudience();
			// 获取附带信息,并进行自定义验证,这里是验证根据userid查出来的用户名与token中附带的用户名是否一致
            Map<String, Claim> claims = jwt.getClaims();
            String userId = claims.get("userId").asString();
            String username = claims.get("username").asString();
            String un = jwtUtil.userService.getUsernameById(userId);
            if (!un.equals(username)) {
                throw new RuntimeException("token无效,请重新登录");
            }
            return true;
        } catch (JWTVerificationException exception) {
            throw new RuntimeException("无效token,请重新获取");
        }
    }

	 /**
     * 获取token携带信息
     * @param token
     * @param name 附带信息名称
     * @return
     */
	public static String getTockenClaims(String token,String name){
        try {
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            JWTVerifier verifier = JWT.require(algorithm)
                    .build();
            DecodedJWT jwt = verifier.verify(token);
            Map<String, Claim> claims = jwt.getClaims();
            return claims.get(name).asString();
        }catch (JWTVerificationException exception) {
            return "";
        }
    }
}

拦截器类

拦截带有@JwtToken注解的请求,有的话进行验证

public class JwtInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        // 从 http 请求头中取出 token
        String token = httpServletRequest.getHeader("token");
        // 如果不是映射到方法直接通过
        if(!(o instanceof HandlerMethod)){
            return true;
        }
        HandlerMethod handlerMethod=(HandlerMethod)o;
        Method method=handlerMethod.getMethod();
        //检查有没有需要用户权限的注解
        if (method.isAnnotationPresent(JwtToken.class)) {
            JwtToken jwtToken = method.getAnnotation(JwtToken.class);
            if (jwtToken.required()) {
                // 执行认证
                if (token == null) {
                    throw new RuntimeException("无token,请重新登录");
                }
                // 验证 token
                JwtUtil.checkSign(token);
            }
        }
        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 {

    }
}

添加至拦截器

@Configuration
public class WebConfig implements WebMvcConfigurer {

    /**
     * @Description: 添加拦截器
     * @Param: [interceptorRegistry]
     * @Return: void
     */
    @Override
    public void addInterceptors(InterceptorRegistry interceptorRegistry) {
        interceptorRegistry.addInterceptor(new JwtInterceptor())
                // 拦截所有请求,通过判断是否有 @JwtToken 注解 决定是否需要登录
                .addPathPatterns("/**");
    }
}

controller请求

使用@JwtToken注解

登录时不使用注解并将生成的token返回给客户端,其他需要进行身份验证的请求时使用@JwtToken

	@RequestMapping(value = "/login",method = RequestMethod.POST)
    public JsonResult login(@RequestParam(value = "username") String username, @RequestParam("password") String password){
        Map<String,Object> record=new HashMap<>();
        record.put("username",username);
        record.put("password",password);
        Map data=userService.login(record);
        if(data!=null){
            String token= JwtUtil.sign(data.get("userId").toString(),username);
            data.put("token",token);
            data.remove("userId");
            return JsonResult.build(1,"success",data);
        }else {
            return JsonResult.build(-1,"用户名或密码错误",null);
        }
    }
	@JwtToken
    @RequestMapping(value = "getList",method = RequestMethod.POST)
    public JsonResult getList(@RequestParam("a") String a){
        Map<String,Object> record=new HashMap<>();
        record.put("a",a);
        List list = userService.getList(record);
        return JsonResult.ok(list);
    }
获取token信息
    @JwtToken
    @PostMapping(("/test"))
    public void test() {
        HttpServletRequest httpServletRequest = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
        String token = httpServletRequest.getHeader("token");
        String username = JwtUtil.getTockenClaims(token,"username");
    }

前端开发请求

登录成功后得到token,可存放在sessionStorage、localStorage或cookie中

方案一:将token添加在header

例如使用axios

/* http request
 **请求拦截器
 **在发送请求之前进行的一系列处理,根据项目要求自行配置
 **例如:loading
 */
axios.interceptors.request.use(
  (config) => {
    // 请求响应时间
    config.timeout = 60 * 1000
    // config.data = JSON.stringify(config.data)
    config.headers = {
      'Content-Type': 'application/x-www-form-urlencoded',
      token: sessionStorage.getItem('accessToken')//获取token
      // 'Content-Type': 'application/json'
    }
    return config
  },
  function(error) {
    // 对请求错误做处理
    return Promise.reject(error)
  }
)

方案二:将token携带在get或post请求的参数中

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java实现Token登录验证可以通过以下步骤来实现: 1. 用户登录时,服务器端生成一个Token,并将Token与用户信息关联存储起来。Token可以是一个随机生成的字符串,也可以使用JWT(JSON Web Token)等标准方式生成。 2. 服务器将生成的Token返回给客户端,在登录接口的响应中包含Token信息。 3. 客户端在后续请求中将Token以特定的方式传递给服务器。常见的方式有将Token放在请求头的Authorization字段中,或者放在请求参数中。 4. 服务器接收到请求后,从请求中获取Token,并根据存储的Token信息进行验证验证方式可以是查询数据库或缓存中的Token信息,或者使用JWT解析Token验证签名等。 5. 如果验证成功,服务器可以根据Token关联的用户信息进行相应操作。如果验证失败,则返回相应的错误信息。 以下是一个简单的示例代码: ```java // 生成Token并关联用户信息 public String generateToken(User user) { // 生成随机字符串作为Token String token = generateRandomString(); // 将Token与用户信息关联存储起来,例如存储在数据库或缓存中 tokenRepository.saveToken(token, user); return token; } // 验证Token public boolean validateToken(String token) { // 查询数据库或缓存中的Token信息 TokenInfo tokenInfo = tokenRepository.getTokenInfo(token); if (tokenInfo != null && tokenInfo.isValid()) { // Token验证通过 return true; } else { // Token验证失败 return false; } } // 示例的登录接口 public ResponseEntity<?> login(String username, String password) { // 根据用户名和密码验证用户身份 User user = userRepository.getUserByUsernameAndPassword(username, password); if (user != null) { // 登录成功,生成Token并返回给客户端 String token = generateToken(user); // 将Token放入响应的头部或作为响应体返回给客户端 HttpHeaders headers = new HttpHeaders(); headers.add("Authorization", "Bearer " + token); return ResponseEntity.ok().headers(headers).build(); } else { // 登录失败 return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } } ``` 请注意,这只是一个简单示例,并未涵盖所有细节。在实际开发中,您可能需要更加完善的实现,并考虑安全性、Token的过期时间、刷新Token等方面的问题。同时也可以结合框架或库来简化Token验证的过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值