一.介绍java
一、JSON Web Token,简称JWT,本质是一个token,是一种紧凑的URL安全方法,用于在网络通讯的双方之间传递。web
二、通常放在HTTP的headers 参数里面的authorization里面,值的前面加Bearer关键字和空格。spring
三、主要用于身份认证和信息交换apache
四、由三部分组成,用英文句点链接(.),例如:xxxxxx.yyyyyy.zzzzzzjson
——认证呢,有不少种,session 认证,basic auth 认证,OAuth认证,token认证等。这里只是介绍了其中基于JWT技术的token认证而已。用token认证,很好解决大型分布式横行扩展问题。api
2、JWT的结构语法:https://blog.csdn.net/buyaoshuohua1/article/details/73739419/安全
3、模仿登陆+过滤器(springboot demo)springboot
(1)流程:服务器
登陆接口未作拦截建立token网络
非登陆接口被过滤器拦截>>验证token是否存在,是否失效>>验证成功则返回,不然就返回
(2)实现:
一、添加依赖
<!--JJWT库--> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.6.0</version> </dependency>
二、TokenObject
package com.example.demo.common.bo; import org.springframework.stereotype.Component; @Component public class TokenObject { /**客户端id*/ private String clientId; /**base64加密*/ private String base64Secret; /**用户名*/ private String name; /**到期时间*/ private long expiresSecond; /**管理员名称*/ private String userName; /**管理员id*/ private Integer aId; /**职能*/ private String role; /**项目名称*/ private String project; public String getClientId() { return clientId; } public void setClientId(String clientId) { this.clientId = clientId; } public String getBase64Secret() { return base64Secret; } public void setBase64Secret(String base64Secret) { this.base64Secret = base64Secret; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getExpiresSecond() { return expiresSecond; } public void setExpiresSecond(long expiresSecond) { this.expiresSecond = expiresSecond; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Integer getaId() { return aId; } public void setaId(Integer aId) { this.aId = aId; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } public String getProject() { return project; } public void setProject(String project) { this.project = project; } }
三、JwtHelper
package com.example.demo.common.utils; import java.util.Date; import javax.crypto.spec.SecretKeySpec; import javax.servlet.http.HttpServletRequest; import javax.xml.bind.DatatypeConverter; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.fastjson.JSONObject; import com.example.demo.common.bo.TokenObject; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.impl.Base64Codec; public class JwtHelper { private static Logger logger = LoggerFactory.getLogger(JwtHelper.class); /** * 校验Token * @param jwt * @param httpRequest * @return */ public static int checkToken(String jwt, HttpServletRequest httpRequest){ if (!StringUtils.isBlank(jwt)){ if (jwt.split("\\.").length==3) { logger.info("jwt:" + jwt); String[] split = jwt.split("\\."); String content = split[1];//负荷 String s = Base64Codec.BASE64URL.decodeToString(content); logger.info("s:" + s); String sign = split[2];//签名 logger.info("sign:" + sign); JSONObject jsonObject1 = JSONObject.parseObject(s); long nowMillis = System.currentTimeMillis(); Date now = new Date(nowMillis); long expiresSecond = (long) jsonObject1.get("expiresSecond"); //判断是否过时 if(now.getTime()>expiresSecond) return 2; TokenObject o = (TokenObject) JSONObject.toJavaObject(jsonObject1, TokenObject.class); // if (o!=null){ // String project = o.getProject(); // // if (!StaticInfo.PROJECT.equals(project)) // return 0; // } String jwtByStr = createJWTByObj(o); String s2 = jwtByStr.split("\\.")[2]; logger.info("s2:" + s2); if (sign.equals(s2)) { logger.info("验证成功"); return 1; } else return 0; } } return 0; } /** * 获取用户id * @param jwt * @return */ public static int getIdByJWT(String jwt){ if (!StringUtils.isBlank(jwt)) { if (jwt.split("\\.").length == 3) { logger.info("jwt:" + jwt); String[] split = jwt.split("\\."); String content = split[1]; String s = Base64Codec.BASE64URL.decodeToString(content); JSONObject jsonObject1 = JSONObject.parseObject(s); TokenObject o = (TokenObject) JSONObject.toJavaObject(jsonObject1, TokenObject.class); return o.getaId(); } } return 0; } /** * 获取用户clinetId * @param jwt * @return */ public static String getClinetIdByJWT(String jwt){ if (!StringUtils.isBlank(jwt)) { if (jwt.split("\\.").length == 3) { logger.info("jwt:" + jwt); String[] split = jwt.split("\\."); String content = split[1]; String s = Base64Codec.BASE64URL.decodeToString(content); JSONObject jsonObject1 = JSONObject.parseObject(s); TokenObject o = (TokenObject) JSONObject.toJavaObject(jsonObject1, TokenObject.class); return o.getClientId(); } } return ""; } /** * 获取客户信息 * @param request * @return * @throws CustomException */ public static int getIdByRequest(HttpServletRequest request) { int i = 0; String auth = request.getHeader("Authorization"); if ((auth != null) && (auth.length() > 6)) { String HeadStr = auth.substring(0, 5).toLowerCase(); if (HeadStr.compareTo("basic") == 0) { auth = auth.substring(6, auth.length()); i = JwtHelper.getIdByJWT(auth); } } if (i==0) // throw new CustomException(ResultEnum.PERMISSION_DENIED); return i; return i; } public static String createJWTByObj(TokenObject tokenObject) { Object jsonObject = JSONObject.toJSON(tokenObject); SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; //long nowMillis = System.currentTimeMillis(); // Date now = new Date(nowMillis); //生成签名密钥 byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(tokenObject.getBase64Secret());//服务器本身定义的秘钥 SecretKeySpec signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName()); //添加构成JWT的参数 JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT") .setHeaderParam("alg", "HS256") .setPayload(jsonObject.toString()) .signWith(signatureAlgorithm, signingKey); //生成JWT return builder.compact(); } }
四、AuthUtil
public class AuthUtil { public static String getClinetIdByAuth(HttpServletRequest request) { HttpServletRequest httpRequest = (HttpServletRequest) request; String auth = httpRequest.getHeader("Authorization"); auth = auth.substring(7, auth.length()); return JwtHelper.getClinetIdByJWT(auth); } }
五、HTTPBasicAuthorizeAttribute
@Order(value = 1) @WebFilter(filterName = "colationFilter", urlPatterns = "/testtoken/*") public class HTTPBasicAuthorizeAttribute implements Filter { private Logger logger = LoggerFactory.getLogger(HTTPBasicAuthorizeAttribute.class); @Override public void destroy() { logger.info("后台token过滤器,溜了溜了溜了溜了"); // 能够日志管理添加 } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { logger.info("后台token过滤器检测"); // 1.检测当前是否须要从新登陆 // if(audience!=null){ // if (audience.getClientId().equals(StaticInfo.SIGNOUT)){ // toResponse((HttpServletResponse) response,1,(HttpServletRequest) // request); // return; // } // } // 2.检测请求同token信息 ResultEnum resultStatusCode = checkHTTPBasicAuthorize(request); if (resultStatusCode.equals(ResultEnum.INVALID_SINGTIMEOUT)) {// 超时 toResponse((HttpServletResponse) response, 2, (HttpServletRequest) request); return; } else if (resultStatusCode.equals(ResultEnum.INVALID_PERMISSION_DENIED)) {// 权限不够 toResponse((HttpServletResponse) response, 0, (HttpServletRequest) request); return; } logger.info("后台token过滤器检测经过"); chain.doFilter(request, response); } /** * 响应 * * @param response * @param i * 类型 * @throws IOException */ private void toResponse(HttpServletResponse response, int i, HttpServletRequest request) throws IOException { HttpServletResponse httpResponse = response; httpResponse.setCharacterEncoding("UTF-8"); httpResponse.setContentType("application/json; charset=utf-8"); httpResponse.setHeader("Access-Control-Allow-Origin", "*"); httpResponse.setHeader("Access-Control-Allow-Credentials", "true"); httpResponse.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,DELETE,PATCH,PUT"); httpResponse.setHeader("Access-Control-Max-Age", "3600"); httpResponse.setHeader("Access-Control-Allow-Headers", "Origin,X-Requested-With,x-requested-with,X-Custom-Header," + "Content-Type,Accept,Authorization"); String method = request.getMethod(); if ("OPTIONS".equalsIgnoreCase(method)) { logger.info("OPTIONS请求"); httpResponse.setStatus(HttpServletResponse.SC_ACCEPTED); } ObjectMapper mapper = new ObjectMapper(); PrintWriter writer = httpResponse.getWriter(); // if (i==1) // writer.write(mapper.writeValueAsString(ResultEnum.RESTARTLOGIN)); if (i == 2) writer.write(mapper.writeValueAsString(ResultEnum.INVALID_SINGTIMEOUT)); else if (i == 0) writer.write(mapper.writeValueAsString(ResultEnum.INVALID_PERMISSION_DENIED)); writer.close(); if (writer != null) writer = null; } @Override public void init(FilterConfig arg0) throws ServletException { logger.info("后台token过滤器启动"); } /** * 检测请求同token信息 * * @param request * @return */ private ResultEnum checkHTTPBasicAuthorize(ServletRequest request) { try { HttpServletRequest httpRequest = (HttpServletRequest) request; String auth = httpRequest.getHeader("Authorization"); if ((auth != null) && (auth.length() > 7)) { String HeadStr = auth.substring(0, 6).toLowerCase(); /*if (HeadStr.compareTo("basic") == 0) { auth = auth.substring(6, auth.length()); int i = JwtHelper.checkToken(auth, httpRequest); if (i == 1) { return ResultEnum.OK; } else if (i == 2) { return ResultEnum.INVALID_SINGTIMEOUT; } else if (i == 0) { return ResultEnum.INVALID_PERMISSION_DENIED; } }*/ if (HeadStr.compareTo("bearer") == 0) { auth = auth.substring(7, auth.length()); int i = JwtHelper.checkToken(auth, httpRequest); if (i == 1) { return ResultEnum.OK; } else if (i == 2) { return ResultEnum.INVALID_SINGTIMEOUT; } else if (i == 0) { return ResultEnum.INVALID_PERMISSION_DENIED; } } } return ResultEnum.INVALID_PERMISSION_DENIED; } catch (Exception ex) { return ResultEnum.INVALID_PERMISSION_DENIED; } } }
六、LoginController
@Api(value = "LoginController") @RequestMapping("/api") @Controller public class LoginController { @ApiOperation(value = "登陆测试方法", notes = "登陆测试方法") @RequestMapping(value = "/login", method = RequestMethod.POST,produces = MediaType.APPLICATION_JSON_UTF8_VALUE) @ResponseBody public ResultModel<String> login(@RequestBody String userName) { System.out.println("用户名:"+userName); // 一、业务逻辑 // 二、返回token TokenObject token = new TokenObject(); token.setBase64Secret("test"); token.setClientId(userName); token.setExpiresSecond(new Date().getTime() + 5*60 * 1000); return ResultModel.success(JwtHelper.createJWTByObj(token)); } }
七、TestTokenController
@Api(value = "TestTokenController") @RequestMapping("/testtoken") @RestController public class TestTokenController { @ApiOperation(value = "token测试方法", notes = "token测试方法") @RequestMapping(value = "/test", method = RequestMethod.POST) public ResultModel<String> test(String p,HttpServletRequest request) { return ResultModel.success(AuthUtil.getClinetIdByAuth(request)); } }
(3)效果:
登陆:
用token访问业务接口: