Jwt简介
JSON Web Token是目前最流行的跨域认证解决方案,,适合前后端分离项目通过Restful API进行数据交互时进行身份认证
Jwt构成(.隔开)
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MTkxNjQ4NjEsInVzZXJuYW1lIjoiYWRtaW4ifQ.fo5a-H_C7XG3fSnNdCEMzM2QmrF5c7yypzoSxGzgJOo
Header(头部):放有签名算法和令牌类型
Payload(负载):你在令牌上附带的信息:比如用户的姓名,这样以后验证了令牌之后就可以直接从这里获取信息而不用再查数据库了
Signature(签名):对前两部分的签名,防止数据篡改
交互流程
本文将通过几个简单步骤教大家如何集成Jwt,废话不多说,直接上步骤。(注:使用了Lombok,需下载好相关插件及依赖)
<!---jwt-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
Login:
username: admin
password: admin
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @author admin
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@NotNull(message = "id不能为空")
private Integer id;
@NotBlank(message="姓名不能为空")
@Length(min = 2, max = 4, message = "name 姓名长度必须在 {min} - {max} 之间")
private String username;
@NotBlank(message="密码不能为空")
@Length(min = 5, max = 10, message = "password 密码长度必须在 {min} - {max} 之间")
private String password;
}
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.apache.commons.lang.StringUtils;
import java.util.Calendar;
/**
* @author admin
*/
public class JWTUtils {
/**
* 获取token
* @param u user
* @return token
*/
public static String getToken(User u) {
Calendar instance = Calendar.getInstance();
//默认令牌过期时间7天
instance.add(Calendar.DATE, 7);
JWTCreator.Builder builder = JWT.create();
builder.withClaim("userId", u.getId())
.withClaim("username", u.getUsername());
return builder.withExpiresAt(instance.getTime())
.sign(Algorithm.HMAC256(u.getPassword()));
}
/**
* 验证token合法性 成功返回token
*/
public static DecodedJWT verify(String token) throws MyException {
if(StringUtils.isEmpty(token)){
throw new MyException("token不能为空");
}
//获取登录用户真正的密码假如数据库查出来的是123456
String password = "admin";
JWTVerifier build = JWT.require(Algorithm.HMAC256(password)).build();
return build.verify(token);
}
/* public static void main(String[] args) {
DecodedJWT verify = verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MTcxMDg1MDAsInVzZXJuYW1lIjoiYWRtaW4ifQ.geBEtpluViRUg66_P7ZisN3I_d4e32Wms8mFoBYM5f0");
System.out.println(verify.getClaim("password").asString());
}*/
}
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.chentawen.springbootall.util.JWTUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author admin
*/
@Slf4j
public class JWTInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String token = request.getHeader("token");
if(StringUtils.isEmpty(token)){
throw new MyException("token不能为空");
}
try {
JWTUtils.verify(token);
} catch (SignatureVerificationException e) {
log.error("无效签名! 错误 ->", e);
return false;
} catch (TokenExpiredException e) {
log.error("token过期! 错误 ->", e);
return false;
} catch (AlgorithmMismatchException e) {
log.error("token算法不一致! 错误 ->", e);
return false;
} catch (Exception e) {
log.error("token无效! 错误 ->", e);
return false;
}
return true;
}
}
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
* @author admin
*/
@Configuration
public class IntercaptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new JWTInterceptor())
//拦截的路径
.addPathPatterns("/**")
//排除登录接口
.excludePathPatterns("/user/login");
}
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author admin
*/
@RestController
@RequestMapping("user")
public class UserLoginController {
@Value("${Login.username}")
private String realUsername;
@Value("${Login.password}")
private String realPassword;
@GetMapping("login")
public String login(String username, String password) {
if (username.equals(realUsername) && password.equals(realPassword)) {
User u = new User();
u.setPassword(password);
u.setUsername(username);
return JWTUtils.getToken(u);
}
return "登录失败!账号或者密码不对!";
}
@GetMapping("test")
public String test() {
return "访问test - API";
}
}
登录接口-返回Jwt
测试接口-返回无权限
测试接口-请求头带token,访问成功
有什么疑问可评论区提问! 求点赞!求转发!求收藏!