第一步:新建项目
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交流: