JWT的快速应用和入门

第一步:新建项目

java哪个版本应该都行。我用的是java8。

第二步:配置maven仓库(预先安装apache)

第三步:pom.xml添加相关依赖,添加打包路径与相关依赖

java 复制代码
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<resources>
<!--项目配置文件所在目录-->
<resource>
<!--Mapper.xml也要编译到项目-->
<directory>src/main/resources</directory>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

第四步:创建配置文件。在resources下创建application.properties

java 复制代码
server.port=9999
#项目根路径
server.servlet.context-path=/
#设置日志级别
logging.level.com.sxjwt=DEBUG
logging.level.root=INFO

第五步:创建测试类与启动类

测试类

java 复制代码
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

@GetMapping("/demo")
public String demo(){
return "demo";
   }
}

启动类

java 复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan("com.jwt")
public class Boostarter {
public static void main(String[] args){
SpringApplication.run(Boostarter.class);
   }
}

启动项目。。。这是成功的情况

第六步:引入redis依赖(假设已经安装并启动redis)

java 复制代码
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-data-redis</artifactId>
 </dependency>    

 <dependency>
 <groupId>org.apache.commons</groupId>
 <artifactId>commons-pool2</artifactId>
 </dependency>

在application.properties中添加:

java 复制代码
#redis
spring.redis.database=0
spring.redis.host=127.0.0.1
spring.redis.port=6379
#可设置密码
#spring.redis.password=
spring.redis.jedis.pool.max-active=50
spring.redis.jedis.pool.max-wait=-1
spring.redis.jedis.pool.max-idle=50
spring.redis.jedis.pool.min-idle=0
spring.redis.timeout=10000

redis测试类:

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RedisController {

@Autowired
private StringRedisTemplate stringRedisTemplate;

@GetMapping("/get")
public Object get(String key){
return stringRedisTemplate.opsForValue().get(key);
   }

@GetMapping("/set")
public Object set(String key,String value){
stringRedisTemplate.opsForValue().set(key,value);
return "ok";
   }
}


第七步:引入jwt有关依赖:

java 复制代码
<!--jwt依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.0</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.70</version>
</dependency>

创建统一返回结果类checkResult:

java 复制代码
import io.jsonwebtoken.Claims;

public class CheckResult {
private boolean Success;
private Claims claims;
private Integer errCode;
public Integer getErrCode() {
return errCode;
   }
public void setErrCode(Integer errCode) {
this.errCode = errCode;
   }
public boolean isSuccess() {
return Success;
        }
public void setSuccess(boolean success) {
Success = success;
   }
public Claims getClaims() {
return claims;
    }
public void setClaims(Claims claims) {
this.claims = claims;
     }
@Override
public String toString() {
return "CheckResult [Success="+ Success + ", claims="+ claims +
", errCode="+ errCode + "]";
        }
}

创建jwt工具类:

java 复制代码
import io.jsonwebtoken.*;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;

public class JwtUtils {
private static final String ENTERPRISE="7th";
private static final String JWT_SECERT = "sxjwt";
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

/**
 * 生成token
 */
public static String createToken(String userInfo, Long ttlMillis) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
SecretKey secretKey = generalKey();
JwtBuilder builder = Jwts.builder().setSubject(userInfo) // 主题
.setIssuer(ENTERPRISE) // 签发者
.setIssuedAt(now) // 签发时间
.signWith(signatureAlgorithm, secretKey); // 签名算法以及密匙
if (ttlMillis >= 0) {
long expMillis = nowMillis + ttlMillis;
Date expDate = new Date(expMillis);
builder.setExpiration(expDate); // 过期时间
}
return builder.compact();
        }

/**
        * 校验token
        */
public static CheckResult validateJWT(String jwtStr) {
CheckResult checkResult = new CheckResult();
Claims claims = null;
try {
claims = parseJWT(jwtStr);
checkResult.setSuccess(true);
checkResult.setClaims(claims);
            } catch (ExpiredJwtException e) {
checkResult.setErrCode(410);
checkResult.setSuccess(false);
            } catch (SignatureException e) {
checkResult.setErrCode(510);
checkResult.setSuccess(false);
            } catch (Exception e) {
checkResult.setErrCode(510);
checkResult.setSuccess(false);
            }
return checkResult;
           }

public static Claims parseJWT(String jwt) throws Exception {
SecretKey secretKey = generalKey();
return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();
        }

public static SecretKey generalKey() {
byte[] encodedKey = Base64.decodeBase64(JWT_SECERT);
SecretKey key = new SecretKeySpec(encodedKey, 0,
encodedKey.length, "AES");
return key;
        }
}

创建自定义注解:@auth

java 复制代码
import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface Auth {
String[] Roles() default {"admin"};
}

创建user实体类:

java 复制代码
import java.util.List;

public class User {
private Integer id;
private String name;
private String pwd;
private List<String>roles;
private String token;
private String refleshToken;

public Integer getId() {
return id;
   }

public void setId(Integer id) {
this.id = id;
   }

public String getName() {
return name;
   }

public void setName(String name) {
this.name = name;
   }

public String getPwd() {
return pwd;
   }

public void setPwd(String pwd) {
this.pwd = pwd;
   }

public List<String>getRoles() {
return roles;
   }

public void setRoles(List<String> roles) {
this.roles = roles;
   }

public String getToken() {
return token;
   }

public void setToken(String token) {
this.token = token;
   }

public String getRefleshToken() {
return refleshToken;
   }

public void setRefleshToken(String refleshToken) {
this.refleshToken = refleshToken;
   }
   @Override
public String toString() {
return "User{"+
"id="+ id +
", name='"+ name + '\'' +
", pwd='"+ pwd + '\'' +
", roles="+ roles +
", token='"+ token + '\'' +
", refleshToken='"+ refleshToken + '\'' +
'}';
}

}

创建json工具类:

java 复制代码
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.List;


public class JsonUtils {
// 定义jackson对象
private static final ObjectMapper MAPPER = new ObjectMapper();

/**
    * 将对象转换成json字符串。
* <p>Title: pojoToJson</p>
    * <p>Description: </p>
    * @param data
* @return
    */
public static String objectToJson(Object data) {
try {
String string = MAPPER.writeValueAsString(data);
return string;
       } catch (JsonProcessingException e) {
           e.printStackTrace();
       }
return null;
   }

/**
    * 将json结果集转化为对象
*
    * @param jsonData json数据
* @param clazz 对象中的object类型
* @return
    */
public static <T>T jsonToPojo(String jsonData, Class<T> beanType) {
try {
T t = MAPPER.readValue(jsonData, beanType);
return t;
       } catch (Exception e) {
           e.printStackTrace();
       }
return null;
   }

/**
    * 将json数据转换成pojo对象list
    * <p>Title: jsonToList</p>
    * <p>Description: </p>
    * @param jsonData
* @param beanType
* @return
    */
public static <T>List<T>jsonToList(String jsonData, Class<T> beanType) {
JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
try {
List<T>list = MAPPER.readValue(jsonData, javaType);
return list;
       } catch (Exception e) {
           e.printStackTrace();
       }

return null;
   }
}

创建登录控制器LoginController

java 复制代码
import com.alibaba.fastjson.JSONObject;

import com.sxjwt.pojo.User;
import com.sxjwt.utils.JwtUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


@RestController
public class LoginController {

@Autowired
StringRedisTemplate stringRedisTemplate;

@RequestMapping("/login")
public Object login(String name,String pwd) throws Exception {
if(StringUtils.isEmpty(name)||StringUtils.isEmpty(pwd)){
throw new Exception("用户名或密码错误");
       }
String md5 = getMD5(pwd);
User user = selectUser(name, md5);
if(user == null){
throw new Exception("用户名或密码错误");
       }
//设置Token
user.setPwd(null);
user.setToken(JwtUtils.createToken(JSONObject.toJSONString(user),1000*20L));
user.setRefleshToken(JwtUtils.createToken(JSONObject.toJSONString(user),1000*60*60*24*365L));
//存入Redis
stringRedisTemplate.opsForValue().set(user.getId()+"",user.getToken());
return user.toString();
   }


//查询用户
private User selectUser(String name, String pwd) {
for (User user : systemUsers) {
if (user.getName().equals(name) &&user.getPwd().equals(pwd)) {
User u =new User();
u.setId(user.getId());
u.setName(user.getName());
u.setRoles(user.getRoles());
return u;
           }
       }
return null;
   }

//密码加密
private static String getMD5(String value) {
String base = value + "/s/"+ "sds2d2ff";
return DigestUtils.md5DigestAsHex(base.getBytes());
   }

//模拟数据库查询
//添加虚拟用户
public static List<User>systemUsers = new ArrayList();
static {
User user1 = new User();
user1.setId(1);
user1.setName("admin");
//123
user1.setPwd("51b274f7949d4ffc4c018283e1b679ea");
user1.setRoles(Arrays.asList(new String[]{"admin"}));


User user2 = new User();
user2.setId(2);
user2.setName("zhang");
//123
user2.setPwd("51b274f7949d4ffc4c018283e1b679ea");
user2.setRoles(Arrays.asList(new String[]{"admin", "user"}));

systemUsers.add(user1);
systemUsers.add(user2);
   }
}

拦截器:

MyInterceptor 和 interceptorConfig

MyInterceptor:

java 复制代码
import com.alibaba.fastjson.JSONObject;

import com.sxjwt.LoginController;
import com.sxjwt.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;


@Component
public class MyInterceptor implements HandlerInterceptor {
@Autowired
private StringRedisTemplate stringRedisTemplate;


@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {

String userId = request.getHeader("userId");
String token = request.getHeader("token");
String refleshToken = request.getHeader("refleshToken");
//校验token是否存在
if (StringUtils.isEmpty(token) || StringUtils.isEmpty(userId)) {
           returnErrorResponse(response, "无权限访问1");
return false;
       }
String userCurrentToken = stringRedisTemplate.opsForValue().get(userId);
if (userCurrentToken == null || !userCurrentToken.equals(token)) {
           returnErrorResponse(response, "无权限访问2");
return false;
       }
//校验token是否过期
CheckResult checkResult = JwtUtils.validateJWT(token);
if (checkResult.isSuccess()) {
//校验权限
if (validateRights(checkResult, response, handler)) {
//放行 将token 返回
response.setHeader("token", token);
               response.setHeader("refleshToken", refleshToken);
return true;
           } else {
               returnErrorResponse(response, "无权限访问3");
return false;
           }
       } else {
//刷新token
CheckResult checkResult1 = JwtUtils.validateJWT(refleshToken);
User user = JSONObject.parseObject(checkResult1.getClaims().getSubject(), User.class);
if (!userId.equals(user.getId() + "")) {
               returnErrorResponse(response, "无权限访问4");
return false;
           }
User u = getOneUser(user.getId());
if (u == null) {
               returnErrorResponse(response, "无权限访问5");
return false;
           }
//设置Token
String newToken = JwtUtils.createToken(JSONObject.toJSONString(u), 1000 * 60 * 60 * 2L);
u.setToken(newToken);
           response.setHeader("token", newToken);
           response.setHeader("refleshToken", JwtUtils.createToken(JSONObject.toJSONString(u), -1L));
//存入Redis
stringRedisTemplate.opsForValue().set(u.getId() + "", newToken);
//校验权限
List<String>roles = u.getRoles();
if (validateRights(roles, response, handler)) {
return true;
           } else {
               returnErrorResponse(response, "无权限访问6");
return false;
           }
       }
   }


public void returnErrorResponse(HttpServletResponse response, Object result) {
OutputStream out = null;
try {
           response.setStatus(403);
           response.setCharacterEncoding("utf-8");
           response.setContentType("text/json");
out = response.getOutputStream();
out.write(JsonUtils.objectToJson(result).getBytes("utf-8"));
out.flush();
       } catch (Exception e) {
           e.printStackTrace();
       } finally {
if (out != null) {
try {
out.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
       }
   }


private boolean validateRights(List<String> userRoles, HttpServletResponse response, Object handler) {
try {
Class<? extends Method>targetClass = ((HandlerMethod) handler).getMethod().getClass();
Auth auth = null;
auth = targetClass.getAnnotation(Auth.class);
if (auth == null) {
Method method = ((HandlerMethod) handler).getMethod();
auth = method.getAnnotation(Auth.class);
           }
//不需要权限校验
if (auth == null) {
return true;
           }
//校验用户是否有权限
String[] roles = auth.Roles();
for (String role : userRoles) {
if (Arrays.asList(roles).contains(role)) {
return true;
               }
           }
return false;
       } catch (Exception e) {
           e.printStackTrace();
return false;
       }
   }

private boolean validateRights(CheckResult checkResult, HttpServletResponse response, Object handler) {
try {
String stringUser = checkResult.getClaims().getSubject();// 获取token信息
User user = JSONObject.parseObject(stringUser, User.class);
List<String>userRoles = user.getRoles();

Class<? extends Method>targetClass = ((HandlerMethod) handler).getMethod().getClass();
Auth auth = null;
auth = targetClass.getAnnotation(Auth.class);
if (auth == null) {
Method method = ((HandlerMethod) handler).getMethod();
auth = method.getAnnotation(Auth.class);
           }
//不需要权限校验
if (auth == null) {
return true;
           }
//校验用户是否有权限
String[] roles = auth.Roles();
for (String role : userRoles) {
if (Arrays.asList(roles).contains(role)) {
return true;
               }
           }
return false;
       } catch (Exception e) {
           e.printStackTrace();
return false;
       }
   }

private User getOneUser(int id) {
List<User>systemUsers = LoginController.systemUsers;
for (User user : systemUsers) {
if (id == user.getId()) {
User u = new User();
u.setId(user.getId());
u.setName(user.getName());
u.setRoles(user.getRoles());
return u;
           }
       }
return null;
   }
}

InterceptorConfig:

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

//注解:决定是否启动拦截器
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
private MyInterceptor MyInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//添加限流拦截器
registry.addInterceptor(MyInterceptor)
               .addPathPatterns("/**")
//放行的路径
.excludePathPatterns("/login");
   }
}

未登录和已登录效果对比:

企鹅交流:
企鹅技术交流群

vx交流:

相关推荐
码蜂窝编程官方几秒前
【含开题报告+文档+PPT+源码】基于SpringBoot+Vue的虎鲸旅游攻略网的设计与实现
java·vue.js·spring boot·后端·spring·旅游
Viktor_Ye16 分钟前
高效集成易快报与金蝶应付单的方案
java·前端·数据库
hummhumm19 分钟前
第 25 章 - Golang 项目结构
java·开发语言·前端·后端·python·elasticsearch·golang
一二小选手23 分钟前
【Maven】IDEA创建Maven项目 Maven配置
java·maven
J老熊29 分钟前
JavaFX:简介、使用场景、常见问题及对比其他框架分析
java·开发语言·后端·面试·系统架构·软件工程
猿java33 分钟前
什么是 Hystrix?它的工作原理是什么?
java·微服务·面试
AuroraI'ncoding35 分钟前
时间请求参数、响应
java·后端·spring
所待.3831 小时前
JavaEE之线程初阶(上)
java·java-ee
Winston Wood1 小时前
Java线程池详解
java·线程池·多线程·性能
手握风云-1 小时前
数据结构(Java版)第二期:包装类和泛型
java·开发语言·数据结构