Json web token 详解(三)
json
适用于现代 C++ 的 JSON。
项目地址:https://gitcode.com/gh_mirrors/js/json

·
下面我们用springmvc和jwt的类库来实现一个例子。
要使用jwt,需要pom.xml中添加如下依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.2.0</version>
</dependency>
下面贴一个完整的pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.jstudioframework</groupId>
<artifactId>jstudio-jwt</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<!-- 设置编码字符集 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 集中定义依赖版本号 -->
<junit.version>4.12</junit.version>
<spring.version>4.3.7.RELEASE</spring.version>
<jackson.version>2.8.4</jackson.version>
<java.jwt.version>3.2.0</java.jwt.version>
<jstl.version>1.2</jstl.version>
<servlet-api.version>2.5</servlet-api.version>
<jsp-api.version>2.2</jsp-api.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>${java.jwt.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- JSP相关 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>${servlet-api.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>${jsp-api.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<!-- 配置插件 -->
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<port>8080</port>
<path>/</path>
<url>http://127.0.0.1:8080/manager/text</url>
<username>tomcat</username>
<password>tomcat</password>
</configuration>
</plugin>
</plugins>
</build>
</project>
一。定义一个jwt的工具类,具有加密和解密token的功能
import java.util.HashMap;
import java.util.Map;
/**
* JwtToken
*/
public class JwtToken {
//密钥
private static final String SECRET = "secret";
//jackson
private static ObjectMapper mapper = new ObjectMapper();
/**
* header数据
* @return
*/
private static Map<String, Object> createHead() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("typ", "JWT");
map.put("alg", "HS256");
return map;
}
/**
* 生成token
*
* @param obj 对象数据
* @param maxAge 有效期
* @param <T>
* @return
*/
public static <T> String sign(T obj, long maxAge) throws UnsupportedEncodingException, JsonProcessingException {
JWTCreator.Builder builder = JWT.create();
builder.withHeader(createHead())//header
.withSubject(mapper.writeValueAsString(obj)); //payload
if (maxAge >= 0) {
long expMillis = System.currentTimeMillis() + maxAge;
Date exp = new Date(expMillis);
builder.withExpiresAt(exp);
}
return builder.sign(Algorithm.HMAC256(SECRET));
}
/**
* 解密
* @param token token字符串
* @param classT 解密后的类型
* @param <T>
* @return
*/
public static <T> T unsign(String token, Class<T> classT) throws IOException {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
DecodedJWT jwt = verifier.verify(token);
Date exp = jwt.getExpiresAt();
if(exp!=null&&exp.after(new Date())){
String subject = jwt.getSubject();
return mapper.readValue(subject, classT);
}
return null;
}
}
二。 登录时根据用户传来的username和password验证身份,如果合法,便给该用户jwt加密生成token
package jwt.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import jwt.JwtToken;
import jwt.model.User;
import jwt.util.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
/**
* 用户登录
*/
@Controller
public class LoginController {
@RequestMapping(value="login", produces = "application/json; charset=utf-8")
@ResponseBody
public ResponseEntity login(HttpServletRequest request, @RequestParam( "username") String username,
@RequestParam("password") String password) throws UnsupportedEncodingException, JsonProcessingException {
ResponseEntity responseEntity = ResponseEntity.ok();
if("admin".equals(username) && "admin".equals(password)) {
//模拟用户数据,真实环境需要到数据库验证
User user = new User();
user.setId(123456);
user.setUsername(username);
//给用户jwt加密生成token
String token = JwtToken.sign(user, 60L * 1000L * 30L);
//封装成对象返回给客户端
responseEntity.putDataValue("userId", user.getId());
responseEntity.putDataValue("token", token);
responseEntity.putDataValue("user", user);
}
else{
responseEntity = ResponseEntity.customerError();
}
return responseEntity;
}
}
User用户类如下
package jwt.model;
/**
* User bean
*/
public class User {
private long id;
private String username;
private String password;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
json
适用于现代 C++ 的 JSON。
项目地址:https://gitcode.com/gh_mirrors/js/json
返回给用户端的一个工具类
package jwt.util;
import java.util.HashMap;
import java.util.Map;
public class ResponseEntity {
public static final String ERRORS_KEY = "errors";
private final String message;
private final int code;
private final Map<String, Object> data = new HashMap();
public String getMessage() {
return message;
}
public int getCode() {
return code;
}
public Map<String, Object> getData() {
return data;
}
public ResponseEntity putDataValue(String key, Object value) {
data.put(key, value);
return this;
}
private ResponseEntity(int code, String message) {
this.code = code;
this.message = message;
}
public static ResponseEntity ok() {
return new ResponseEntity(200, "Ok");
}
public static ResponseEntity notFound() {
return new ResponseEntity(404, "Not Found");
}
public static ResponseEntity badRequest() {
return new ResponseEntity(400, "Bad Request");
}
public static ResponseEntity forbidden() {
return new ResponseEntity(403, "Forbidden");
}
public static ResponseEntity unauthorized() {
return new ResponseEntity(401, "unauthorized");
}
public static ResponseEntity serverInternalError() {
return new ResponseEntity(500, "Server Internal Error");
}
public static ResponseEntity customerError() {
return new ResponseEntity(1001, "Customer Error");
}
}
三。在用户登录后获得userId和token,以后用户每次请求时,都得带上这两个参数,后台拿到token后解密出userId,与用户传递过来的userId比较,如果相同,则说明用户身份合法。这里用springmvc的拦截器实现验证。
注意:测试使用Params传递参数的,建议正式环境在header里添加参数
package jwt.interceptor;
import com.fasterxml.jackson.databind.ObjectMapper;
import jwt.JwtToken;
import jwt.model.User;
import jwt.util.ResponseEntity;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
/**
* Token验证拦截器
*/
public class UserTokenInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
String token = request.getParameter("token");
ResponseEntity responseData = ResponseEntity.ok();
//token不存在
if (token != null) {
User user = JwtToken.unsign(token, User.class);
String userId = request.getParameter("userId");
//解密token后的userId与用户传来的userId不一致,大多是因为token过期
if (user != null && userId != null && Integer.parseInt(userId) == user.getId()) {
return true;
}
}
responseData = ResponseEntity.forbidden();
response.setContentType("application/json; charset=utf-8");
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(responseData);
PrintWriter out = response.getWriter();
out.print(json);
out.flush();
out.close();
return false;
}
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
四。springmvc的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="jwt.controller"/>
<mvc:annotation-driven />
<!-- 拦截器设置 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 匹配的是url路径, 如果不配置或/**,将拦截所有的Controller -->
<mvc:mapping path="/**" />
<!-- /register 和 /login 不需要拦截-->
<mvc:exclude-mapping path="/register" />
<mvc:exclude-mapping path="/login" />
<bean class="jwt.interceptor.UserTokenInterceptor"></bean>
</mvc:interceptor>
<!-- 当设置多个拦截器时,先按顺序调用preHandle方法,然后逆序调用每个拦截器的postHandle和afterCompletion方法 -->
</mvc:interceptors>
<!-- 默认的视图解析器 在上边的解析错误时使用 (默认使用html)- -->
<bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="contentType" value="text/html"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
<property name="order" value="1"/>
</bean>
</beans>
五。 使用Chrome插件Postman进行简单的测试
1.登录,http://localhost:8080/login
、
记下 token和userId
2. 测试token鉴权 http://localhost:8080/info
输入正确的userId和token
注意:测试使用Params传递参数的,建议正式环境在header里添加参数
输入错误的userId或token,在拦截器那里就被拦截了
推荐内容
阅读全文
AI总结




适用于现代 C++ 的 JSON。
最近提交(Master分支:6 个月前 )
51a77f1d
8 小时前
756ca22e
8 小时前
更多推荐
相关推荐
查看更多
json

适用于现代 C++ 的 JSON。
json

An efficient JSON decoder
json

C++ header-only JSON library
热门开源项目
活动日历
查看更多
直播时间 2025-04-23 19:00:00

GitTalk:国内首个微服务编排框架Juggle实战解析
直播时间 2025-04-22 18:31:56

字节AI 黑科技!从 Manus Agent 入门 Eino
直播时间 2025-04-09 14:34:18

樱花限定季|G-Star校园行&华中师范大学专场
直播时间 2025-04-07 14:51:20

樱花限定季|G-Star校园行&华中农业大学专场
直播时间 2025-03-26 14:30:09

开源工业物联实战!
所有评论(0)