介绍:接下来我会把学习阶段学到的框架等知识点进行整合,每一次整合是在前一章的基础上进行的,所以后面的整合不会重复放前面的代码。每次的demo我放在结尾,本次是接着上一章的内容延续的,只增加新增的或者修改的代码。
整合token,每次请求接口时进行token效验,效验通过才可以请求到接口,我是通过jwt生成的token。token个人理解大概就是用来判断用户登录状态,是否已登录的。
首先展示一下目录结构,是根据前面几章进行的增加(原因:内容过多),如下:
第一步:新增依赖(在pom文件增加)
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--swagger --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <!--swagger-ui.html模式 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency> <!--doc.html模式 --> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> <version>1.9.2</version> </dependency> <!-- https://mvnrepository.com/artifact/com.auth0/java-jwt --> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.9.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.json/json --> <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>20190722</version> </dependency> </dependencies>
其实就增加了jwt和json两个依赖。
第二步:新增配置类
TokenInterceptor类(拦截器):
@Component public class TokenInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //跨域请求会首先发一个option请求,直接返回正常状态并通过拦截器 if(request.getMethod().equals("OPTIONS")){ response.setStatus(HttpServletResponse.SC_OK); return true; } response.setCharacterEncoding("utf-8"); String token = request.getHeader("token"); if (token!=null){ boolean result= TokenUtils.verify(token); if (result){ System.out.println("通过拦截器"); return true; } } response.setContentType("application/json; charset=utf-8"); try { JSONObject json=new JSONObject(); json.put("msg","token verify fail"); json.put("code","500"); response.getWriter().append(json.toString()); System.out.println("认证失败,未通过拦截器"); } catch (Exception e) { return false; } /** * 还可以在此处检验用户存不存在等操作 */ return false; } }
PS:此处token从request里面获取header里面的key值是token,你要根据自己的情况来,你在前端header里面传的token叫什么名称,这里就取什么名字。
WebConfiguration类(配置拦截器):
@Configuration public class WebConfiguration implements WebMvcConfigurer { @Autowired private TokenInterceptor tokenInterceptor; /** * 解决跨域请求 * @param registry */ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedHeaders("*") .allowedMethods("*") // .allowedOrigins("*") .allowedOriginPatterns("*") .allowCredentials(true); } /** * 异步请求配置 * @param configurer */ @Override public void configureAsyncSupport(AsyncSupportConfigurer configurer) { configurer.setTaskExecutor(new ConcurrentTaskExecutor(Executors.newFixedThreadPool(3))); configurer.setDefaultTimeout(30000); } /** * 配置拦截器、拦截路径 * 每次请求到拦截的路径,就会去执行拦截器中的方法 * @param configurer */ @Override public void addInterceptors(InterceptorRegistry registry) { List<String> excludePath = new ArrayList<>(); //排除拦截,除了注册登录(此时还没token),其他都拦截 excludePath.add("/userController/login"); //登录 excludePath.add("/userController/register"); //注册 excludePath.add("/doc.html"); //swagger excludePath.add("/swagger-ui.html"); //swagger excludePath.add("/swagger-resources/**"); //swagger excludePath.add("/v2/api-docs"); //swagger excludePath.add("/webjars/**"); //swagger // excludePath.add("/static/**"); //静态资源 // excludePath.add("/assets/**"); //静态资源 registry.addInterceptor(tokenInterceptor) .addPathPatterns("/**") .excludePathPatterns(excludePath); WebMvcConfigurer.super.addInterceptors(registry); } }
PS:addInterceptors方法里面需要按自己情况进行修改,excludePath集合add的是需要放行的接口路径,前几章整合了swagger,所以此处需要放行swagger相关的路径,swagger-ui.html、doc.html、swagger-resources、等等,你再加上自己想要放行的接口路径即可,一般是首页请求的接口以及登录注册的接口(不需要进行token效验的接口)。
第三步:新增token工具类(用来生成token以及效验token)
public class TokenUtils { //token到期时间10小时 private static final long EXPIRE_TIME= 10*60*60*1000; //密钥盐 private static final String TOKEN_SECRET="ljdyaishijin**3nkjnj??"; /** * 生成token * @param user * @return */ public static String sign(User user){ String token=null; try { Date expireAt=new Date(System.currentTimeMillis()+EXPIRE_TIME); token = JWT.create() //发行人 .withIssuer("auth0") //存放数据 .withClaim("username",user.getUserName()) //过期时间 .withExpiresAt(expireAt) .sign(Algorithm.HMAC256(TOKEN_SECRET)); } catch (IllegalArgumentException|JWTCreationException je) { } return token; } /** * token验证 * @param token * @return */ public static Boolean verify(String token){ try { //创建token验证器 JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).withIssuer("auth0").build(); DecodedJWT decodedJWT=jwtVerifier.verify(token); System.out.println("认证通过:"); System.out.println("username: " + decodedJWT.getClaim("username").asString()); System.out.println("过期时间: " + decodedJWT.getExpiresAt()); } catch (IllegalArgumentException |JWTVerificationException e) { //抛出错误即为验证不通过 return false; } return true; } }
PS:此处到期时间可以自定义按情况进行设置,1000是1秒。此处token的生成方法以及效验方法可以根据具体情况进行更改,生成token1是使用的jwt,此处验证方法存在一个用户有多个token的情况(可以同时多次登陆同一账号,重新请求token之后,前一次的token只要没有过期也能使用。),可以整合redis后进行改造(后面会讲到),可以达到一个用户只有一个token的效果(重新请求token之后,前一次的token即使没有过期也不能使用。)
第四步:改造登陆接口
@ApiOperation(value = "登录") @GetMapping("/login") @ApiImplicitParams({ @ApiImplicitParam(name = "userName", value = "用户名", paramType = "String"), @ApiImplicitParam(name = "passWord", value = "密码", paramType = "String") }) public BaseResponse<HashMap> login(@RequestParam(value = "userName") String userName, @RequestParam(value = "passWord") String passWord) throws JsonProcessingException { //包装token User user = new User(); user.setUserName(userName); user.setPassword(passWord); String token= TokenUtils.sign(user); HashMap<String,Object> hs=new HashMap<>(); hs.put("token",token); return RespGenerator.returnOK(hs); }
PS:可以根据自己的情况包装数据作为登录请求的返回结果。
第五步:演示结果
1、当请求没有放行的接口不带token请求时:
结果:会提示token效验失败。
2、当请求放行的接口不带token请求时:
结果:成功请求到接口,此处是登陆接口,返回了token。
3、当请求没有放行的接口带token请求时:
结果:成功请求到接口。
本期整合到此完毕,接下来会继续更新加强整合,尽情期待。
访问地址:http://localhost:8085/swagger-ui.html或者http://localhost:8085/doc.html