Json web token

it2022-06-23  127

转载自:https://blog.csdn.net/zsg88/article/details/76892551

 

下面我们用springmvc和jwt的类库来实现一个例子。

要使用jwt,需要pom.xml中添加如下依赖

 

[java]  view plain  copy   <dependency>      <groupId>com.auth0</groupId>      <artifactId>java-jwt</artifactId>      <version>3.2.0</version>  </dependency>  

 

下面贴一个完整的pom.xml

 

[html]  view plain  copy   <?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的功能

 

[java]  view plain  copy   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

 

[java]  view plain  copy   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用户类如下

 

[java]  view plain  copy   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;      }  }  

 

返回给用户端的一个工具类

 

[java]  view plain  copy   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里添加参数

 

 

[java]  view plain  copy   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的配置

 

 

[html]  view plain  copy   <?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,在拦截器那里就被拦截了

转载于:https://www.cnblogs.com/jay36/p/8716445.html


最新回复(0)