前面一篇介绍了springboot同时集成shiro和jwt实现的登录检验,权限控制功能,但是我们有时候仅仅需要进行一个登录校验而不需要权限的控制,那么我们就只需要集成jwt即可。
一、编写用户实体类
package com.sf.gis.boot.rcboot.jwt;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
* @author 80004819
* @ClassName:
* @Description:
* @date 2020年09月11日 17:27:58
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class User {
private String userName;
private String password;
}
二、jwt工具类:生成token和校验token
package com.sf.gis.boot.rcboot.jwt;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* @author 80004819
* @ClassName:
* @Description:
* @date 2020年09月11日 17:26:55
*/
@Slf4j
public class JwtUtil {
/**
* 密钥
*/
private static final String SECRET = "my_secret";
/**
* 过期时间
**/
private static final long EXPIRATION = 1800L;//单位为秒
/**
* 生成用户token,设置token超时时间
*/
public static String createToken(User user) {
//过期时间
Date expireDate = new Date(System.currentTimeMillis() + EXPIRATION * 1000);
Map<String, Object> map = new HashMap<>();
map.put("alg", "HS256");
map.put("typ", "JWT");
String token = JWT.create()
.withHeader(map)// 添加头部
//可以将基本信息放到claims中
.withClaim("userName", user.getUserName())//userId
.withClaim("password", user.getUserName())//userName
.withExpiresAt(expireDate) //超时设置,设置过期的日期
.withIssuedAt(new Date()) //签发时间
.sign(Algorithm.HMAC256(SECRET)); //SECRET加密
return token;
}
/**
* 校验token并解析token
*/
public static Map<String, Claim> verifyToken(String token) {
DecodedJWT jwt = null;
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
jwt = verifier.verify(token);
} catch (Exception e) {
log.error(e.getMessage());
log.error("token解码异常");
//解码异常则抛出异常
return null;
}
return jwt.getClaims();
}
}
三、JwtFilter 实现Filter接口
package com.sf.gis.boot.rcboot.jwt;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.interfaces.Claim;
import com.google.gson.Gson;
import com.sf.gis.boot.rcboot.util.JsonResponse;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
/**
* @author 80004819
* @ClassName:
* @Description:
* @date 2020年09月11日 17:34:49
*/
@Slf4j
//直接使用注解方式注册过滤器,需要在启动类上添加@ServletComponentScan注解
//@WebFilter(filterName = "JwtFilter", urlPatterns = "/*")
public class JwtFilter implements Filter {
private static final Gson GSON = new Gson();
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
//设置编码格式
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("UTF-8");
//获取 header里的token
final String token = request.getHeader("authorization");
if ("OPTIONS".equals(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
chain.doFilter(request, response);
}
// Except OPTIONS, other request should be checked by JWT
else {
String requestURI = request.getRequestURI();
if (isPass(requestURI)) {
chain.doFilter(req, res);
return;
}
if (token == null) {
response.getWriter().write(GSON.toJson(JsonResponse.error("没有token")));
return;
}
//如果获取到了token,验证token是否合法
Map<String, Claim> userData = JwtUtil.verifyToken(token);
if (userData == null) {
response.getWriter().write(GSON.toJson(JsonResponse.error("token不合法!")));
return;
}
String userName = userData.get("userName").asString();
String password = userData.get("password").asString();
//拦截器 拿到用户信息,放到request中
// request.setAttribute("userName", userName);
// request.setAttribute("password", password);
chain.doFilter(req, res);
}
}
/**
* 直接通行的uri
*
* @param requestURI
* @return
*/
private boolean isPass(String requestURI) {
return StrUtil.equals(requestURI, "/") || StrUtil.startWithIgnoreCase(requestURI, "/jwt/getToken") ||
StrUtil.startWithIgnoreCase(requestURI, "/swagger-ui.html") ||
StrUtil.startWithIgnoreCase(requestURI, "/error")
|| StrUtil.startWithIgnoreCase(requestURI, "/csrf")
|| StrUtil.containsAnyIgnoreCase(requestURI, "v2/api-docs", "swagger");
}
@Override
public void destroy() {
}
}
四、 JwtConfig 如果不使用注解式注册过滤器,则可以使用代码注册方式注册过滤器
package com.sf.gis.boot.rcboot.jwt;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author 80004819
* @ClassName:
* @Description:
* @date 2020年09月11日 17:47:32
*/
@Configuration
public class JwtConfig {
@Bean
public FilterRegistrationBean filterRegistrationBean (){
FilterRegistrationBean filterRegistrationBean= new FilterRegistrationBean();
JwtFilter jwtFilter = new JwtFilter();
filterRegistrationBean.setFilter(jwtFilter);
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
}
五、编写测试controller
package com.sf.gis.boot.rcboot.controller;
import com.sf.gis.boot.rcboot.shiro.JWTUtil;
import com.sf.gis.boot.rcboot.util.JsonResponse;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 80004819
* @ClassName:
* @Description:
* @date 2020年09月11日 17:38:09
*/
@RestController
@RequestMapping("/jwt")
@Slf4j
@Api(tags = "JWT权限controller")
public class JwtTokenController {
/**
* 模拟登陆接口获取到token,有效期为30分钟
*
* @return
*/
@GetMapping("/getToken")
public JsonResponse getToken() {
try {
//String token = JWTUtil.createToken(new User("admin", "123456"));
String token = JWTUtil.sign("admin", "123456", false);
return JsonResponse.ok(JsonResponse.STATUS_SUCCESS, token);
} catch (Exception e) {
log.error("error", e);
return JsonResponse.error("获取token失败");
}
}
}
请求接口,会生成一个token字符串,我们需要在请求其他的接口的时候,在请求头设置
authorization = 生成的token