環(huán)境配置
JDK:1.8 MAVEN:3.6.1 IDE:19.3 TOMCAT:8 MYSQL:5.7 swagger-ui2
基本框架搭建
可參考本人博客地址
https://blog.csdn.net/qq_41998978/article/details/103362147
添加TOKEN驗(yàn)證
pom.xml文件加入以下
<!-- jwt -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>2.2.0</version>
</dependency>
JWT加密解密工具類
/**
* 項(xiàng)目名:AutomobileModelTradingPlatform
* 日 期:2020/2/9
* 包 名:com.item.utile
*
* @author: LiuJia
* Copyright 2019 403
*/
package com.item.utile;
import com.auth0.jwt.JWTSigner;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.internal.com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
import java.util.Map;
public class JWT {
private static final String SECRET = "XX#$%()(#*!()!KL<><MQLMNQNQJQK sdfkjsdrow32234545fdf>?N<:{LWPW";
private static final String EXP = "exp";
private static final String PAYLOAD = "payload";
//加密,傳入一個(gè)對(duì)象和有效期
public static <T> String sign(T object, long maxAge) {
try {
final JWTSigner signer = new JWTSigner(SECRET);
final Map<String, Object> claims = new HashMap<String, Object>();
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(object);
claims.put(PAYLOAD, jsonString);
claims.put(EXP, System.currentTimeMillis() + maxAge);
return signer.sign(claims);
} catch(Exception e) {
return null;
}
}
//解密,傳入一個(gè)加密后的token字符串和解密后的類型
public static<T> T unsign(String jwt, Class<T> classT) {
final JWTVerifier verifier = new JWTVerifier(SECRET);
try {
final Map<String,Object> claims= verifier.verify(jwt);
if (claims.containsKey(EXP) && claims.containsKey(PAYLOAD)) {
long exp = (Long)claims.get(EXP);
long currentTimeMillis = System.currentTimeMillis();
if (exp > currentTimeMillis) {
String json = (String)claims.get(PAYLOAD);
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(json, classT);
}
}
return null;
} catch (Exception e) {
return null;
}
}
}
SSM中攔截器判斷TOKEN工具類
/**
* 項(xiàng)目名:AutomobileModelTradingPlatform
* 日 期:2020/2/4
* 包 名:com.item.utile
*
* @author: LiuJia
* Copyright 2019 403
*/
package com.item.utile;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.item.entity.Adminuser;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSONObject;
public class TokenInterceptor implements HandlerInterceptor {
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception arg3)
throws Exception {
}
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView model) throws Exception {
}
//攔截每個(gè)請(qǐng)求
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
response.setCharacterEncoding("utf-8");
//讀取請(qǐng)求頭中的Token信息
String token = request.getHeader("token");
//判斷token是否存在
if (null != token) {
//獲取token中的實(shí)體類信息
Adminuser adminuser = JWT.unsign(token, Adminuser.class);
//獲取請(qǐng)求頭中用戶id信息
String userId = request.getHeader("userId");
//判斷token是否合法
if (null != userId && null != adminuser) {
//解密token后得到的用戶id和請(qǐng)求頭中的用戶對(duì)比
if (Integer.parseInt(userId) == adminuser.getId()) {
return true;
} else {
//這里的ResponseData是包裝的json工具類
ResponseData responseData = ResponseData.customerError("token已過期");
responseMessage(response, response.getWriter(), responseData);
return false;
}
} else {
ResponseData responseData = ResponseData.customerError("token無效");
responseMessage(response, response.getWriter(), responseData);
return false;
}
} else {
ResponseData responseData = ResponseData.customerError("無token");
responseMessage(response, response.getWriter(), responseData);
return false;
}
}
//請(qǐng)求不通過,返回錯(cuò)誤信息給客戶端
private void responseMessage(HttpServletResponse response, PrintWriter out, ResponseData responseData) {
response.setContentType("application/json; charset=utf-8");
String json = JSONObject.toJSONString(responseData);
out.print(json);
out.flush();
out.close();
}
}
spring-mvc.xml配置文件加入攔截器
<mvc:interceptors>
<mvc:interceptor>
<!-- 設(shè)置攔截的路徑 -->
<mvc:mapping path="/Api/**"/>
<!-- 設(shè)置放開攔截的路徑,這里是登錄 -->
<mvc:exclude-mapping path="/Api/userApi/login"/>
<!-- 指定自己的攔截器工具類路徑-->
<bean class="com.item.utile.TokenInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
<!--這里配置返回json時(shí)可能出現(xiàn)亂碼。處理亂碼-->
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="text/plain;charset=UTF-8"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
用于返回給客戶端的json包裝類
/**
* 項(xiàng)目名:AutomobileModelTradingPlatform
* 日 期:2020/2/9
* 包 名:com.item.utile
*
* @author: LiuJia
* Copyright 2019 xiaojiajia
*/
package com.item.utile;
import java.util.HashMap;
import java.util.Map;
public class ResponseData {
private final String message;
private final int code;
private final Map<String, Object> data = new HashMap<String, Object>();
public String getMessage() {
return message;
}
public int getCode() {
return code;
}
public Map<String, Object> getData() {
return data;
}
public ResponseData putDataValue(String key, Object value) {
data.put(key, value);
return this;
}
private ResponseData(int code, String message) {
this.code = code;
this.message = message;
}
public static ResponseData ok() {
return new ResponseData(200, "訪問成功");
}
public static ResponseData notFound() {
return new ResponseData(404, "服務(wù)器丟失");
}
public static ResponseData badRequest() {
return new ResponseData(400, "服務(wù)器錯(cuò)誤");
}
public static ResponseData forbidden() {
return new ResponseData(403, "系統(tǒng)錯(cuò)誤");
}
public static ResponseData unauthorized() {
return new ResponseData(401, "未經(jīng)授權(quán)");
}
public static ResponseData serverInternalError() {
return new ResponseData(500, "服務(wù)器內(nèi)部錯(cuò)誤");
}
public static ResponseData customerError(String message) {
return new ResponseData(1001, message);
}
}
處理登錄
@RequestMapping("/login")
public Object login(String userName, String userPwd) {
//這里采用的是封裝工具查詢,此處不做說明
AdminuserExample adminuserExample = new AdminuserExample();
AdminuserExample.Criteria criteria = adminuserExample.createCriteria();
criteria.andAdminusercodeEqualTo(userName);
List<Adminuser> adminuserList = adminuserService.selectByExample(adminuserExample);
if (adminuserList.size() > 0) {
if (adminuserList.get(0).getAdminuserpwd().equals(userPwd)) {
//登錄成功
//生成加密token
String token = JWT.sign(adminuserList.get(0), 60L * 1000L * 30L);
//返回給客戶端的信息
ResponseData responseData = ResponseData.ok();
responseData.putDataValue("userId", adminuserList.get(0).getId());
responseData.putDataValue("token", token);
responseData.putDataValue("user", adminuserList.get(0));
return responseData;
} else {
ResponseData responseData = ResponseData.customerError("密碼錯(cuò)誤");
return responseData;
}
} else {
ResponseData responseData = ResponseData.customerError("無效用戶名");
return responseData;
}
}
驗(yàn)證說明:在之后請(qǐng)求接口時(shí),前端需要在請(qǐng)求頭中帶上“userId”和“token”兩個(gè)參數(shù),解密token后和前端傳來的用戶id對(duì)比,以此判斷token的合法性。
加入Swagger-ui接口文檔
pom.xml文件加入
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
SwaggerConfiguration工具類
/**
* 項(xiàng)目名:eep
* 日 期:2020/2/10
* 包 名:com.item.utile
*
* @author: Liujia
* Copyright 2019 xiaojiajiaK3
*/
package com.item.utile;
import com.google.common.collect.Lists;
import io.swagger.annotations.ApiOperation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;
import static springfox.documentation.builders.PathSelectors.regex;
@Configuration
@EnableSwagger2
//@Profile({"prod"})
public class SwaggerConfiguration {
@Bean
public Docket platformApi() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).forCodeGeneration(true)
.select().apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(regex("^.*(?<!error)$"))
.build()
.securitySchemes(securitySchemes())
.securityContexts(securityContexts())
.pathMapping("/")
;
}
private List<ApiKey> securitySchemes() {
return Lists.newArrayList(
//這里配置兩個(gè)全局頭請(qǐng)求-跟上面token驗(yàn)證配套
new ApiKey("token", "token", "header"),
new ApiKey("userId", "userId", "header")
);
}
private List<SecurityContext> securityContexts() {
return Lists.newArrayList(
SecurityContext.builder()
.securityReferences(defaultAuth())
.build()
);
}
List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "認(rèn)證權(quán)限");
return Lists.newArrayList(
//這里配置兩個(gè)頭請(qǐng)求-每個(gè)接口-跟上面token驗(yàn)證配套
new SecurityReference("token", new AuthorizationScope[]{authorizationScope}),
new SecurityReference("userId", new AuthorizationScope[]{authorizationScope})
);
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("xxx平臺(tái)接口文檔").description("?xiaojiajiaK3")
.termsOfServiceUrl("https://blog.csdn.net/qq_41998978")
.contact(new Contact("xxx交易平臺(tái)", "", "xiaojiajia981225@outlook.com")).license("Apache License Version 2.0")
.licenseUrl("https://blog.csdn.net/qq_41998978").version("2.0").build();
}
}
spring-mvc.xml配置文件加入
<!-- 加載SwaggerConfig 類名改成自己創(chuàng)建的-->
<bean class="com.item.utile.SwaggerConfiguration"/>
<!-- 將靜態(tài)資源交由默認(rèn)的servlet處理--沒有這句的加上這句 -->
<mvc:default-servlet-handler/>
使用
//控制器加入
@Api(tags = "xxx接口")
//方法加入
@ApiOperation(value="xxx接口",notes = "這是notes描述",httpMethod = "GET--請(qǐng)求方式")
注意事項(xiàng)
//這些注解用于解決跨域訪問的問題
@RestController
@CrossOrigin
//web.xml文件中若沒有以下配置要加上
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<!-- 匹配所有請(qǐng)求,此處也可以配置成 *.do 形式 -->
<!--/*.do是對(duì)所有以.do結(jié)尾的請(qǐng)求做處理,/*是對(duì)所有請(qǐng)求做處理-->
<url-pattern>/</url-pattern>
</servlet-mapping>
效果圖
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述