300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > 史上最简单的JWT教程 看不懂来捶我!

史上最简单的JWT教程 看不懂来捶我!

时间:2022-06-15 20:39:40

相关推荐

史上最简单的JWT教程 看不懂来捶我!

史上最简单的Elasticsearch教程已经开始更新!

(帮到到您请点点关注,文章持续更新中!)

(个人Git主页:/Mydreamandreality)

JWT鉴权机制:我放狠话出去,看不懂尽管来捶我(反正你也锤不到如果有不懂的可以留言一起交流学习,关注一哈,之后会更新Elasticsearch,cloud Java的干货,一起学习,博客是在印象笔记的记录,copy出来样式有一些乱,见谅1. JWT是什么?1. JWT是一种基于JSON的令牌安全验证(在某些特定的场合可以替代Session或者Cookie)2. JWT是什么样子的?1. JWT是由三个部分组成的,分别是:1. 头部信息(header)1. 作用:指定该JWT使用的签名2. 消息体(playload)1. 作用:JWT的请求数据3. 签名( signatrue)1. 签名是三个部分组合成的1. Base64编码后的头部信息,消息体,且加密后拼接而成,[,]分割2. 私有的Key计算,并且Base64编码3. JWT该怎么用?1. JWT经常被用来保护服务器的资源,客户端一般通过HTTP/header的Authorzation把JWT发送给服务端2. 服务端使用自己保存的Key进行计算,验证签名JWT是否合法

生产项目中JWT的使用

代码:

/*** Created by 張燿峰* JWT常量* @author 孤* @date /1/2* @Varsion 1.0*/public interface JwtConstants {String AUTH_HEADER = "Authorization";String SECRET = "defaultSecret";String AUTH_PATH = "/attackApi/auth";Long EXPIRATION = 604800L;}//AUTH_HEADER 是HTTPHeader请求的参数//SECRET 是具体的加密算法//AUTH_PATH是提供给客户端获取JWT参数的接口/需要提供正确的用户名以及密码//EXPIRATION是计算JWT过期时间需要用到的

/*** Created by 張燿峰* RestApi鉴权拦截器* @author 孤* @date /1/2* @Varsion 1.0*/public class RestApiInteceptor extends HandlerInterceptorAdapter {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {//此处应是静态资源请求if (handler instanceof org.springframework.web.servlet.resource.ResourceHttpRequestHandler) {return true;}return check(request,response);}/*** toKen检查* @return*/private boolean check(HttpServletRequest request, HttpServletResponse response) {//此处是指获取Token的接口if (request.getServletPath().equals(JwtConstants.AUTH_PATH)) {return true;}final String requestHeader = request.getHeader(JwtConstants.AUTH_HEADER);String authToken = null;if (requestHeader != null && requestHeader.startsWith("attackFind ")) {authToken = requestHeader.substring(11);try {//包含了验证jwt是否正确boolean isExpired = AuthUtil.isTokenExpired(authToken);if (isExpired) {RenderUtil.renderJson(response, new ErrorResponseData(BizExceptionEnum.TOKEN_EXPIRED.getCode(), BizExceptionEnum.TOKEN_EXPIRED.getMessage()));return false;}} catch (JwtException e) {//有异常就是token解析失败RenderUtil.renderJson(response, new ErrorResponseData(BizExceptionEnum.TOKEN_ERROR.getCode(), BizExceptionEnum.TOKEN_ERROR.getMessage()));return false;}} else {RenderUtil.renderJson(response, new ErrorResponseData(BizExceptionEnum.TOKEN_ERROR.getCode(), BizExceptionEnum.TOKEN_ERROR.getMessage()));return false;}return true;}}//preHandle://首先需要判断请求是否是静态资源//如果是则不验证该请求,不是则执行check方法//check中先验证该请求是否为获取JWT参数//获取请求头中的Authorization参数信息//调用我们接口的第三方约定好JWT之前追加attackFind ,如果没有这个信息那么JWT就验证失败//isTokenExpired是检测JWT是否过期 true过期

/*** Created by 張燿峰* <p>Jwt工具类</p>* jwt的claim里一般包含以下几种数据:* 1. iss -- token的发行者* 2. sub -- 该JWT所面向的用户* 3. aud -- 接收该JWT的一方* 4. exp -- token的失效时间* 5. nbf -- 在此时间段之前,不会被处理* 6. iat -- jwt发布时间* 7. jti -- jwt唯一标识,防止重复使用** @author 孤* @date /1/2* @Varsion 1.0*/public class AuthUtil {/*** 从Token中获取用户名称** @param token* @return 用户名称*/public static String getUserNameFromToken(String token) {return getClaimsFromToken(token).getSubject();}/*** 从Token中获取JWT发布时间** @param token* @return 发布时间*/public static Date getIsseudAtDateFromToken(String token) {return getClaimsFromToken(token).getIssuedAt();}/*** 从Token中获取JWT过期时间** @param token* @return 过期时间*/public static Date getExPirationDateFromToken(String token) {return getClaimsFromToken(token).getExpiration();}/*** 从Token中获取JWT接收者** @param token* @return 接收者*/public static String getAyduebceFromToken(String token) {return getClaimsFromToken(token).getAudience();}/*** 从Token中获取私有的JWT claim** @param token* @param key* @return claim*/public static String getPrivateClaimsFromToken(String token, String key) {return getClaimsFromToken(token).get(key).toString();}public static Claims getClaimsFromToken(String token) {return Jwts.parser().setSigningKey(JwtConstants.SECRET).parseClaimsJws(token).getBody();}/*** 检查Token是否正确** @param token*/public static void parseToken(String token) {Jwts.parser().setSigningKey(JwtConstants.SECRET).parseClaimsJws(token).getBody();}/*** 检查Token是否过期** @param token* @return false未过期 true过期*/public static boolean isTokenExpired(String token) {try {final Date expiration = getExPirationDateFromToken(token);return expiration.before(new Date());} catch (ExpiredJwtException expiredJwtException) {return true;}}/*** 生成Token** @param userId* @return Token*/public static String generateToken(String userId) {Map<String, Object> claims = new HashMap<>();return doGeneratorToken(claims, userId);}private static String doGeneratorToken(Map<String, Object> claims, String subject) {final Date startDate = new Date();final Date endDate = new Date(startDate.getTime() + JwtConstants.EXPIRATION * 1000);return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(startDate).setExpiration(endDate).signWith(SignatureAlgorithm.HS512,JwtConstants.SECRET).compact();}/*** 获取混淆MD5签名用的随机字符串*/public static String getRandomKey() {return ToolUtil.getRandomString(6);}//这个类中的代码都是JWT的工具/*** 自动渲染当前用户信息登录属性 的过滤器*/public class AttributeSetInteceptor extends HandlerInterceptorAdapter {@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {//没有视图的直接跳过过滤器if (modelAndView == null || modelAndView.getViewName() == null) {return;}//视图结尾不是html的直接跳过if (!modelAndView.getViewName().endsWith("html")) {return;}ShiroUser user = ShiroKit.getUser();if (user == null) {throw new AuthenticationException("当前没有登录账号!");} else {modelAndView.addObject("menus", user.getId());modelAndView.addObject("name", user.getName());}}}//业务代码无需关注

@Configurationpublic class WebConfig implements WebMvcConfigurer {@Autowiredprivate AttackProperties attackProperties;/*** 增加swagger的支持*/@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {if (attackProperties.getSwaggerOpen()) {registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");}}/*** 增加对rest api鉴权的spring mvc拦截器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {List<String> NONE_PERMISSION_RES = CollectionUtil.newLinkedList("/static/**", "/attackApi/**", "/login", "/global/sessionError", "/kaptcha","/cornemail","/init/start","/websocket/new_message","/global/error","/api/**");registry.addInterceptor(new RestApiInteceptor()).addPathPatterns("/attackApi/**");registry.addInterceptor(new AttributeSetInteceptor()).excludePathPatterns(NONE_PERMISSION_RES).addPathPatterns("/**");}/*** 默认错误页面,返回json*/@Bean("error")public AttackErrorView error() {return new AttackErrorView();}....................其他代码省略}

//由于提供给第三方服务时项目是用ShiroSession会话管理管控的//现在要在此基础上增加JWT鉴权//所以过滤 attackApi/**的请求,[不通过Shiro认证,JWT拦截器会拦截attackApi/**的请求]//此处没有使用Shiro就不用关注Map<String, String> hashMap = new LinkedHashMap<>();List<String> NONE_PERMISSION_RES = CollectionUtil.newLinkedList("/static/**", "/attackApi/**", "/login", "/global/sessionError", "/kaptcha","/cornemail","/init/start","/websocket/new_message","/global/error","/api/**");for (String nonePermissionRe : NONE_PERMISSION_RES) {hashMap.put(nonePermissionRe, "anon");}hashMap.put("/**", "user");shiroFilter.setFilterChainDefinitionMap(hashMap);

/*** Created by 張燿峰** @author 孤* @date /1/2* @Varsion 1.0*/@RestController@RequestMapping(value = "/attackApi")public class AttackApi extends BaseController {@Autowiredprivate UserMapper userMapper;@RequestMapping("/auth")public Object auth(@RequestParam("username") String username,@RequestParam("password") String password) {//封装请求账号密码为shiro可验证的tokenUsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password.toCharArray());//获取数据库中的账号密码,准备比对User user = userMapper.getByAccount(username);if (user == null) {return new ErrorResponseData(BizExceptionEnum.ACCOUNT_OR_PWD_ERROR.getCode(), BizExceptionEnum.ACCOUNT_OR_PWD_ERROR.getMessage());}String credentials = user.getPassword();String salt = user.getSalt();ByteSource credentialsSalt = new Md5Hash(salt);SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(new ShiroUser(), credentials, credentialsSalt, "");//校验用户账号密码HashedCredentialsMatcher md5CredentialsMatcher = new HashedCredentialsMatcher();md5CredentialsMatcher.setHashAlgorithmName(ShiroKit.hashAlgorithmName);md5CredentialsMatcher.setHashIterations(ShiroKit.hashIterations);boolean passwordTrueFlag = md5CredentialsMatcher.doCredentialsMatch(usernamePasswordToken, simpleAuthenticationInfo);if (passwordTrueFlag) {HashMap<String, Object> result = new HashMap<>();result.put("token", AuthUtil.generateToken(String.valueOf(user.getId())));return result;} else {return new ErrorResponseData(BizExceptionEnum.ACCOUNT_OR_PWD_ERROR.getCode(), BizExceptionEnum.ACCOUNT_OR_PWD_ERROR.getMessage());}}/*** 测试接口是否走鉴权*/@GetMapping(value = "/test")public Object test() {return SUCCESS_TIP;}//首先访问attackApi/auth接口,用正确的用户密码获取JWT//请求attackApi/test 接口 什么都不携带会抛出令牌验证失败的异常//在Header中携带Authorization:attackFind jwt参数//验证成功

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。