文章目录
1.2. 基于JWT(JSON WEB TOKEN)的Token认证机制实现
session
等 {
"typ": "JWT",
"alg": "HS256"
}
{ "iss": "Online JWT Builder",
"iat": 1416797419,
"exp": 1448333419,
"aud": "www.example.com",
"sub": "jrocket@example.com",
"GivenName": "Johnny",
"Surname": "Rocket",
"Email": "jrocket@example.com",
"Role": [ "Manager", "Project Administrator" ]
}
.
分隔(头部在前),最后将拼接后的字符串和秘钥(secret)用头部指定的算法进行加密得到一个字符串。那么此时完整的JWT的内容就是头部+载荷+最后加密得到的字符串,中间用.
分割<!-- jjwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
/**
* 生成token
*/
@Test
public void test1() {
//eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxIiwiaWF0IjoxNTQ1NTc0ODE1LCJzdWIiOiLpmYjliqDlhbUifQ.WF0VoGSP5oH0XRsCraJ9lRjtVFRs6I0KJpkhFngpwgk
JwtBuilder builder = Jwts.builder()
.setId("1") //用户Id
.setIssuedAt(new Date()) //用户登录的日期
.setSubject("陈加兵")//用户名
.signWith(SignatureAlgorithm.HS256, "sercet"); //指定签名的算法和秘钥(盐)
String token = builder.compact(); //获取生成的token
System.out.println(token);
}
/*
* 解析token
*/
@Test
public void test2() {
Claims claims = Jwts.parser()
.setSigningKey("sercet") //设置解析的秘钥
.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxIiwiaWF0IjoxNTQ1NTc0ODE1LCJzdWIiOiLpmYjliqDlhbUifQ.WF0VoGSP5oH0XRsCraJ9lRjtVFRs6I0KJpkhFngpwgk")
.getBody();
System.out.println("用户Id:"+claims.getId());
System.out.println("用户名:"+claims.getSubject());
System.out.println("登录时间:"+claims.getIssuedAt());
}
JwtBuilder setExpiration(Date exp);
JwtBuilder builder = Jwts.builder()
.setId("1") //用户Id
.setIssuedAt(new Date()) //用户登录的日期
.setSubject("陈加兵")//用户名
.setExpiration(new Date(new Date().getTime()+1000*60*60)) //设置过期时间为1小时
.signWith(SignatureAlgorithm.HS256, "sercet"); //指定签名的算法和秘钥(盐)
JwtBuilder claim(String name, Object value);
: 直接添加自定义的属性,key-value形式JwtBuilder addClaims(Map<String, Object> claims);
: 直接添加一个Map作为自定义的属性/**
* 生成token
*/
@Test
public void test1() {
JwtBuilder builder = Jwts.builder()
.setId("1") //用户Id
.setIssuedAt(new Date()) //用户登录的日期
.setSubject("陈加兵")//用户名
.setExpiration(new Date(new Date().getTime()+1000*60*60)) //设置过期时间为1小时
.signWith(SignatureAlgorithm.HS256, "sercet") //指定签名的算法和秘钥(盐)
.claim("age", 22) //自定义内容
.claim("address", "江苏省"); //自定义内容
String token = builder.compact(); //获取生成的token
System.out.println(token);
}
/*
* 解析token
*/
@Test
public void test2() {
Claims claims = Jwts.parser()
.setSigningKey("sercet") //设置解析的秘钥
.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxIiwiaWF0IjoxNTQ1NTc1ODQzLCJzdWIiOiLpmYjliqDlhbUiLCJleHAiOjE1NDU1Nzk0NDMsImFnZSI6MjIsImFkZHJlc3MiOiLmsZ_oi4_nnIEifQ.uRhzSnsWl5IO-K6SA3zHsqGacZzkOOsFlD8lvqYDleY")
.getBody();
System.out.println("用户Id:"+claims.getId());
System.out.println("用户名:"+claims.getSubject());
System.out.println("登录时间:"+claims.getIssuedAt());
System.out.println("过期时间:"+claims.getExpiration());
System.out.println("address:"+claims.get("address"));
}
import java.util.Date;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Data;
/**
* JWT的工具类
*/
@Component
@ConfigurationProperties(prefix="jwt.config") //读取配置文件中的配置
@Data
public class JwtUtil {
private String secret; //秘钥
private long expire; //过期时间
/**
* 生成token
* @param id 用户的Id
* @param subject 用户名
* @param role 角色,分为用户和后台管理员
* @return
*/
public String encoder(String id,String subject,String role) throws Exception{
JwtBuilder builder = Jwts.builder()
.setId(id) //用户Id
.setIssuedAt(new Date()) //用户登录的日期
.setSubject(subject)//用户名
.setExpiration(new Date(new Date().getTime()+expire)) //设置过期时间为1小时
.claim("role",role) //自定义属性,指定角色
.signWith(SignatureAlgorithm.HS256, secret); //指定签名的算法和秘钥(盐)
return builder.compact();
}
/**
* 对token进行解码
* @param token
* @return 解码后的结果集,相当于Map
* @throws Exception 如果解码失败会抛出异常
*/
public Claims decoder(String token) throws Exception{
return Jwts.parser()
.setSigningKey(secret) //设置解析的秘钥
.parseClaimsJws(token) //解析的token
.getBody();
}
}
jwt: # JWT的配置
config:
secret: secret ## 秘钥
expire: 3600000 ## 过期时间1个小时
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import cn.tedu.auth.util.JwtUtil;
import io.jsonwebtoken.Claims;
/**
* JWT验证token的拦截器
* 改进: 如果没有权限,那么可以跳转到一个指定的错误页面护.......
*/
public class JwtInterceptor extends HandlerInterceptorAdapter {
@Resource
private JwtUtil jwtUtil; //注入JwtUtil
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//获取请求头中的token
String token=request.getHeader("token");
if (StringUtils.isEmpty(token)) {
response.setStatus(HttpStatus.UNAUTHORIZED.value()); //设置401响应信息,没有权限
System.err.println("没有权限");
return false; //直接拦截,不继续进行
}
//如果有token,需要解码
Claims claims=null;
try {
System.err.println(token);
claims = jwtUtil.decoder(token);
if (claims!=null) {
request.setAttribute("claims", claims); //放置在request中,后续的接口可能还需使用
}
} catch (Exception e) {
response.setStatus(HttpStatus.UNAUTHORIZED.value()); //设置401响应信息,没有权限
return false;
}
return true;
}
}
@Configuration
public class webConfig extends WebMvcConfigurerAdapter {
/**
* 注入拦截器,这里一定需要提前注入,否则拦截器中注入的对象将无法注入
*
* @return
*/
@Bean
public JwtInterceptor jwtInterceptor() {
return new JwtInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册自定义拦截器,添加拦截路径和排除拦截路径 ,这里直接使用上面的方法直接获取注入的拦截器即可,否则将会造成拦截器中无法注入其他的对象
registry.addInterceptor(jwtInterceptor()).addPathPatterns("/**").excludePathPatterns("/user/test")
.excludePathPatterns("/user/login");
}
}
public ResultInfo login(User user)throws Exception{
ResultInfo resultInfo=new ResultInfo();
User user2 = userRepository.findByName(user.getName());
if (user2==null) {
resultInfo.setCode("-1");
resultInfo.setMessage("用户名不存在");
return resultInfo;
}
//判断密码是否正确
if (!bCryptPasswordEncoder.matches(user.getPassword(),user2.getPassword())) {
resultInfo.setCode("-1");
resultInfo.setMessage("密码不正确");
return resultInfo;
}
//生成token
String token=JwtUtil.encoder(user2.getId()+"", user2.getName(),"user");
System.err.println(token);
Map<String, Object> map=new HashMap<>();
map.put("token", token); //返回token
map.put("user", user);
resultInfo.setData(map);
resultInfo.setMessage("登录成功");
return resultInfo;
}
/**
* 删除用户
* @param id
* @return
*/
@DeleteMapping("/{id}")
public ResultInfo deleteById(@PathVariable("id")Integer id,HttpServletRequest request) {
ResultInfo resultInfo=new ResultInfo();
//验证角色,之后该段可以直接用切面完成
Claims claims = (Claims) request.getAttribute("claims"); //获取token解析的map
String role=(String) claims.get("role"); //获取角色
if (!"user".equals(role)) {
resultInfo.setCode("-1");
resultInfo.setMessage("权限不足!");
return resultInfo;
}
try {
resultInfo=userService.deleteById(id);
return resultInfo;
} catch (Exception e) {
resultInfo.setCode("-1");
resultInfo.setMessage("异常");
return resultInfo;
}
}