目录
第一步:新增依赖(在pom文件增加)
第二步:新增配置类
第三步:新增token工具类(用来生成token以及效验token)
第四步:改造登陆接口
第五步:演示结果
介绍:接下来我会把学习阶段学到的框架等知识点进行整合,每一次整合是在前一章的基础上进行的,所以后面的整合不会重复放前面的代码。每次的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