赞
踩
token三大组成:
1、header:头部信息
2、payload:存放自己想要的信息
3、sign:是为了防止恶意篡改数据
1、什么是jwt:
java web token (jwt)是目前最流行的跨域身份验证解决方案
在没有跨域和没有分布式的情况下,基本验证方式是通过将session_id存入cookie中,这样每次访问将session_id带入。
还有一种方式是将session持久化,简单的说就是将session存到数据库中,这样的不好处就是持久层坏掉的话,整个认证系统都会死掉,但是现在很多项目用到了这个方式,将session存在redis中。
当然,我们次按在重点研究jwt,他的原理就是会话数据只保存在客户端,每次请求都会被发送到服务器,
2、jwt的原则
现在服务端身份验证之后,生成一个验证数据传给用户,之后,当用户与服务器通信时,客户在请求中发回验证数据。
3、jwt的数据结构
验证数据是一个很长的字符串,他就是有我们之前说过的那三部分组成,header,负载和签名。
其中JWT头是一个源数据的json对象,如:
```java
{
"alg": "HS256",
"typ": "JWT"
}
``
alg属性表示签名使用的算法,默认为HMAC SHA256(写为HS256);typ属性表示令牌的类型,JWT令牌统一写为JWT。
有效负载也是一个json串。JWT指定七个默认字段供选择。
iss:发行人
exp:到期时间
sub:主题
aud:用户
nbf:在此之前不可用
iat:发布时间
jti:JWT ID用于标识该JWT
除以上默认字段外,我们还可以自定义私有字段,如下例:
{
"sub": "1234567890",
"name": "chongchong",
"admin": true
}
签名哈希部分是对上面两部分数据签名,通过指定的算法生成哈希,以确保数据不会被篡改。
jwt有很多jar包来让自己使用,不过还是自己写一个适合自己的最好不过了
现在我们使用springboot来 实现jwt
1、maven
redis.clients
jedis
3.0.0
org.springframework.boot
spring-boot-starter-web
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.2
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.22</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.54</version> </dependency> </dependencies>
2、写一个自定义纾解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthToken {
}
3、WebAppconfiguration
@Configuration
public class WebAppConfiguration implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TokemInterceptor()).addPathPatterns("/**");
}
}
4、创建拦截器
现在就是核心实现点了
```java public class TokemInterceptor implements HandlerInterceptor { Logger log = LoggerFactory.getLogger(TokemInterceptor.class); //存放鉴权信息的Header名称,默认是Authorization private String Authorization = "Authorization"; //鉴权失败后返回的HTTP错误码,默认为401 private int unauthorizedErrorCode = HttpServletResponse.SC_UNAUTHORIZED; /** * 存放用户名称和对应的key */ public static final String USER_KEY = "USER_KEY"; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (!(handler instanceof HandlerMethod)) { return true; } HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); //验证token if (method.getAnnotation(AuthToken.class) != null || handlerMethod.getBeanType().getAnnotation(AuthToken.class) != null) { String token = request.getParameter(Authorization); log.info("获取到的token为: {} ", token); //此处主要设置你的redis的ip和端口号,我的redis是在本地 Jedis jedis = new Jedis("127.0.0.1", 6379); String username = null; if (token != null && token.length() != 0) { //从redis中根据键token来获取绑定的username username = jedis.get(token); log.info("从redis中获取的用户名称为: {}", username); } //判断username不为空的时候 if (username != null && !username.trim().equals("")) { String startBirthTime = jedis.get(token + username); log.info("生成token的时间为: {}", startBirthTime); Long time = System.currentTimeMillis() - Long.valueOf(startBirthTime); log.info("token存在时间为 : {} ms", time); //重新设置Redis中的token过期时间 if (time > CommonUtil.TOKEN_RESET_TIME) { jedis.expire(username, CommonUtil.TOKEN_EXPIRE_TIME); jedis.expire(token, CommonUtil.TOKEN_EXPIRE_TIME); log.info("重置成功!"); Long newBirthTime = System.currentTimeMillis(); jedis.set(token + username, newBirthTime.toString()); } //关闭资源 jedis.close(); request.setAttribute(USER_KEY, username); return true; } else { JSONObject jsonObject = new JSONObject(); PrintWriter out = null; try { response.setStatus(unauthorizedErrorCode); response.setContentType(MediaType.APPLICATION_JSON_VALUE); jsonObject.put("code", ((HttpServletResponse) response).getStatus()); //鉴权失败后返回的错误信息,默认为401 unauthorized jsonObject.put("message", HttpStatus.UNAUTHORIZED); out = response.getWriter(); out.println(jsonObject); return false; } catch (Exception e) { e.printStackTrace(); } finally { if (null != out) { out.flush(); out.close(); } } } } request.setAttribute(USER_KEY, null); 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 { } }
最后,在登录的时候添加token信息,在其他接口添加Token注解
下次我们实战一个非常棒的案例。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。