tnblog
首页
视频
资源
登录

Spring boot +swagger+token

6714人阅读 2021/11/3 15:23 总访问:1590544 评论:0 收藏:0 手机
分类: Java

文章借鉴于://https://www.jianshu.com/p/6e5ee9dd5a61

一、pom的相关依赖

  1. <!--版本控制2.5.5-->
  2. <parent>
  3.    <groupId>org.springframework.boot</groupId>
  4.    <artifactId>spring-boot-starter-parent</artifactId>
  5.    <version>2.5.5</version>  <!--版本控制2.5.5-->
  6.    <relativePath/>
  7. </parent>
  8. <!--web-->
  9. <dependency>
  10. <groupId>org.springframework.boot</groupId>
  11. <artifactId>spring-boot-starter-web</artifactId>
  12. </dependency>
  13. <!--lombok-->
  14. <dependency>
  15. <groupId>org.projectlombok</groupId>
  16. <artifactId>lombok</artifactId>
  17. <optional>true</optional>
  18. </dependency>
  19. <!--swagger-->
  20. <dependency>
  21. <groupId>io.springfox</groupId>
  22. <artifactId>springfox-swagger-ui</artifactId>
  23. <version>2.9.2</version>
  24. </dependency>
  25. <dependency>
  26. <groupId>io.springfox</groupId>
  27. <artifactId>springfox-swagger2</artifactId>
  28. <version>2.9.2</version>
  29. </dependency>
  30. <!--JWT-->
  31. <dependency>
  32. <groupId>com.auth0</groupId>
  33. <artifactId>java-jwt</artifactId>
  34. <version>3.10.0</version>
  35. </dependency>
  36. <dependency>
  37. <groupId>io.jsonwebtoken</groupId>
  38. <artifactId>jjwt</artifactId>
  39. <version>0.9.0</version>
  40. </dependency>
  41. <dependency>
  42. <groupId>commons-codec</groupId>
  43. <artifactId>commons-codec</artifactId>
  44. <version>1.9</version>
  45. </dependency>


二、swagger 的配置
导入相关的包

  1. import org.springframework.context.annotation.Bean;
  2. import org.springframework.context.annotation.Configuration;
  3. import springfox.documentation.builders.PathSelectors;
  4. import springfox.documentation.builders.RequestHandlerSelectors;
  5. import springfox.documentation.service.*;
  6. import springfox.documentation.spi.DocumentationType;
  7. import springfox.documentation.spi.service.contexts.SecurityContext;
  8. import springfox.documentation.spring.web.plugins.Docket;
  9. import springfox.documentation.swagger2.annotations.EnableSwagger2;
  10. import java.util.List;
  1. @Configuration
  2. @EnableSwagger2
  3. public class SwaggerConfig2 {  //https://www.jianshu.com/p/6e5ee9dd5a61
  4.     @Bean
  5.     public Docket api(){
  6.         return new Docket(DocumentationType.SWAGGER_2).
  7.              useDefaultResponseMessages(false)
  8.                 .select()
  9.                 .apis(RequestHandlerSelectors.any())
  10.                 .paths(PathSelectors.regex("^(?!auth).*$"))
  11.                 .build()
  12.                 .securitySchemes(securitySchemes())
  13.                 .securityContexts(securityContexts());//
  14.     }
  15.     private List<ApiKey> securitySchemes()
  16.     {
  17.         return newArrayList( new ApiKey("Authorization""Authorization","header"));
  18.     }
  19.     private List<SecurityContext> securityContexts() {
  20.         return newArrayList(
  21.                 SecurityContext.builder()
  22.                         .securityReferences(defaultAuth())
  23.                         .forPaths(PathSelectors.regex("^(?!auth).*$"))//含有auth路径的接口可以没有令牌
  24.                         .build()
  25.         );
  26.     }
  27.     List<SecurityReference> defaultAuth() {
  28.         AuthorizationScope authorizationScope = new AuthorizationScope("global""accessEverything");
  29.         AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
  30.         authorizationScopes[0] = authorizationScope;
  31.         return newArrayList(
  32.                 new SecurityReference("Authorization", authorizationScopes));
  33.     }
  34. }
  1. 1、配完后会出现这个


2、下图是这个按钮的内容


三、配置toke令牌的加密、解密
1、类Constant的字段设置

  1. public final static String TOKEN_HEADER_STRING="Authorization";
  2. public final static String TOKEN_PERFIX="Bearer";
  3. public final static String CURRENT_USER="name";
  4. public final static String BASE_PATH_PERFIX="/api/practice/v1";


2、toke的配置


导入的包

  1. import com.example.My1101.pojo.Constant;
  2. import io.jsonwebtoken.Claims;
  3. import io.jsonwebtoken.JwtBuilder;
  4. import io.jsonwebtoken.Jwts;
  5. import io.jsonwebtoken.SignatureAlgorithm;
  6. import org.apache.commons.codec.binary.Base64;
  7. import org.springframework.stereotype.Component;
  8. import javax.crypto.SecretKey;
  9. import javax.crypto.spec.SecretKeySpec;
  10. import java.util.Calendar;
  11. import java.util.Date;
  12. import java.util.HashMap;
  1. //SpringBoot中组件类需要使用@Component进行组件注册才能使用(不知道该类属于什么层就可以用它,如:服务处、Dao等)
  2. @Component
  3. public class TokenUtils {
  4.     /**
  5.      * 由字符串生成加密key
  6.      * @return
  7.      */
  8.     public static SecretKey generalKey() {
  9.         String stringKey = "thisisasecretkey"//随机写的
  10.         // 本地的密码解码
  11.         byte[] encodedKey = Base64.decodeBase64(stringKey);
  12.         // 根据给定的字节数组使用AES加密算法构造一个密钥
  13.         SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
  14.         return key;
  15.     }
  16.     /**
  17.      * 生成JWT
  18.      * @return
  19.      */
  20.     public static String createToken(String userName) {
  21.         //设置JWT的header
  22.         HashMap<String, Object> map = new HashMap<String, Object>();
  23.         //Head
  24.         map.put("alg""HS256");
  25.         map.put("typ""jwt");
  26.         //Payload
  27.         map.put("username", userName); //根据userName生成jwt
  28.         //设置JWT的过期时间
  29.         Calendar now = Calendar.getInstance();
  30.         now.add(Calendar.MINUTE, 20);//当前时间+20mins
  31.         Date expireDate = now.getTime();//Calendar转Date
  32.         //设置JWT生效时间
  33.         Date nowDate = new Date();//系统当前时间
  34.         SecretKey key = generalKey(); //密钥(服务端专有,面向客户端隐藏)
  35.         JwtBuilder jwtBuilder = Jwts.builder()
  36.                 .setClaims(map)
  37.                 .setExpiration(expireDate)
  38.                 .setNotBefore(nowDate)
  39.                 //Signature
  40.                 .signWith(SignatureAlgorithm.HS256, key);//设置签发算法和密钥
  41.         return Constant.TOKEN_PERFIX + jwtBuilder.compact();//jwt前面一般会加上Bearer
  42.     }
  43.     /**
  44.      * 解析token
  45.      * @param token
  46.      * @return
  47.      */
  48.     public static Claims parseToken(String token) {
  49.         SecretKey key = generalKey();
  50.         try {
  51.             Claims claims = Jwts.parser()
  52.                     .setSigningKey(key)
  53.                     .parseClaimsJws(token.replace("Bearer""")).getBody();//TOKEN_PERFIX = "Bearer"
  54.             return claims;
  55.         } catch (Exception e) {
  56.             throw new IllegalStateException("Invalid token." + e.getMessage());
  57.         }
  58.     }
  59. }

四、拦截的具体逻辑
导入的包

  1. import com.example.My1101.pojo.Constant;
  2. import io.jsonwebtoken.Claims;
  3. import io.swagger.models.HttpMethod;
  4. import org.springframework.stereotype.Component;
  5. import org.springframework.web.servlet.HandlerInterceptor;
  6. import org.slf4j.Logger;
  7. import org.slf4j.LoggerFactory;
  8. import org.springframework.web.servlet.ModelAndView;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletResponse;
  11. import java.util.Date;
  1. @Component //拦截器也是一个组件,需要加@Component注解进行组件注册
  2. public class AuthInterceptor implements HandlerInterceptor {
  3.     //声明一个static final的Logger对象
  4.     private static final Logger logger = LoggerFactory.getLogger(AuthInterceptor.class);
  5.     /**
  6.      * 预处理回调方法,实现处理器的预处理
  7.      * 返回值:true表示继续流程;false表示流程中断,不会继续调用其他的拦截器或处理器
  8.      */
  9.     @Override
  10.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  11. //        return HandlerInterceptor.super.preHandle(request, response, handler);
  12.         System.out.println("开始拦截.........");
  13.         //设置response的编码格式
  14.         response.setContentType("text/html;charset=utf-8");
  15.         //获取请求的url
  16.         String url = request.getServletPath().toString();
  17.         System.out.println("url:" + url);
  18.         //判断放行的url
  19.         if(url.contains("/user/login")){
  20.             return true;
  21.         }
  22.         if(url.contains("/user/test2")){
  23.             return true;
  24.         }
  25.         if(url.contains("/swagger-resource")){
  26.             return true;
  27.         }
  28.         if(url.contains("/v2/api-docs")){
  29.             return true;
  30.         }
  31.         //第一次请求放行(因为它是探路用的)
  32.         if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
  33.             System.out.println("OPTIONS请求,放行");
  34.             return true;
  35.         }
  36.         //获取request中的参数token
  37.         String token = request.getHeader(Constant.TOKEN_HEADER_STRING);
  38.         //如果token为空或不存在
  39.         if(token==null || "".equals(token) || !token.startsWith(Constant.TOKEN_PERFIX)){
  40.             logger.info("{} : Unknown token", request.getServletPath());
  41.             //将结果打印返回到前端
  42.             response.getWriter().print("The resource requires authentication, which was not supplied with the request");
  43.             return false;//拦截成功
  44.         }
  45.         //解析token
  46.         Claims claims = TokenUtils.parseToken(token);
  47.         String userName = (String)claims.get("username");
  48.         Date expireTime = claims.getExpiration();
  49.         //如果token的username不存在 ,具体的逻辑自己发挥
  50.         if(userName.equals(null)){
  51.             logger.info("{} : token user not found", request.getServletPath());
  52.             response.getWriter().print("ERROR Permission denied");
  53.             return false;
  54.         }
  55.         //如果token过期
  56.         if(expireTime.before(new Date())){
  57.             logger.info("{} : token expired", request.getServletPath());
  58.             response.getWriter().print("The token expired, please apply for a new one");
  59.             return false;
  60.         }
  61.         //token匹配成功,放行
  62.         request.setAttribute(Constant.CURRENT_USER, userName);
  63.         System.out.println("放行...........");
  64.         return true;
  65.     }
  66.     /**
  67.      * 后处理回调方法,实现处理器(controller)的后处理,但在渲染视图之前
  68.      * 此时我们可以通过modelAndView对模型数据进行处理或对视图进行处理
  69.      */
  70.     @Override
  71.     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  72. //        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
  73.     }
  74.     /**
  75.      * 整个请求处理完毕回调方法,即在视图渲染完毕时回调,
  76.      * 如性能监控中我们可以在此记录结束时间并输出消耗时间,
  77.      * 还可以进行一些资源清理,类似于try-catch-finally中的finally,
  78.      * 但仅调用处理器执行链中
  79.      */
  80.     @Override
  81.     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  82. //        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
  83.     }
  84. }

五、配置mvc 实现拦截

导入的包

  1. import com.example.My1101.pojo.Constant;
  2. import com.example.My1101.utils.AuthInterceptor;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
  6. import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
  7. import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  1. @Configuration
  2. public class WebMvcConfig implements WebMvcConfigurer {
  3.     @Autowired
  4.     AuthInterceptor authInterceptor;
  5.     /**
  6.      * 添加拦截器
  7.      * addPathPatterns 用于添加拦截规则,/**表示拦截所有请求
  8.      * excludePathPatterns 排除拦截
  9.      * @param registry
  10.      */
  11.     @Override
  12.     public void addInterceptors(InterceptorRegistry registry) {
  13.         //注册AuthInterceptor拦截器
  14.         registry.addInterceptor(authInterceptor).addPathPatterns(Constant.BASE_PATH_PERFIX +"/**"//拦截/api/practice/v1/user/test
  15.                 .excludePathPatterns(Constant.BASE_PATH_PERFIX + "/user/login"); //放行/api/practice/v1/user/login
  16.     }
  17.     // 这个方法是用来配置静态资源的,比如html,js,css,等等
  18.     @Override
  19.     public void addResourceHandlers(ResourceHandlerRegistry registry) {
  20.     }
  21. }

六、controller层的应用

  1. @Api("用户操作接口")
  2. @RestController("user")
  3. @RequestMapping("/api/practice/v1" + "/user"//配置网址前缀 BASE_PATH_PERFIX = "/api/practice/v1"
  4. public class UserController {
  5.     @Autowired
  6.     UserService userService;
  7.     @ApiOperation(value = "登录", notes = "通过用户名和密码登录系统"//配置方法操作在swagger中的名和曾 notes为备注
  8.     @PostMapping(value = "login")
  9.     public String login(@RequestBody User user) {
  10.         if (user == null) {
  11.             return "用户名或密码为空!";
  12.         }
  13.         User loginUser = userService.login(user);
  14.         if (loginUser == null) {
  15.             return "用户名或密码错误!";
  16.         }
  17.         //生成token(用户拿着这个token+请求返回给服务端,服务端匹配token,如果匹配上了则处理用户发来的请求,如果匹配不上则用户验证失败不处理请求)
  18.         String jwt = TokenUtils.createToken(user.getUserName());
  19.         HashMap<String, String> map = new HashMap<>();
  20.         map.put("token", jwt);
  21.         return ResponseEntity.ok("loginUser").toString() + map;
  22.     }
  23.     @ApiOperation(value = "测试", notes = "通过用户名和密码测试token")
  24.     @PostMapping(value = "test/{toke}")
  25.     public String testToken(User user,String toke){
  26.         return user.toString();
  27.     }
  28.     @ApiOperation(value = "测试2", notes = "通过用户名和密码测试token")
  29.     @PostMapping(value = "test2")
  30.     public String testToken2(User user){
  31.         return user.toString();
  32.     }
  33. }


评价
没有个性,不需要签名
排名
4
文章
473
粉丝
3
评论
2
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术