1 SSM整合Swagger2
1.1 介绍
Swagger是一套围绕OpenAPI规范构建的开源工具,可以帮助您设计,构建,记录和使用REST API。
swagger 能够根据代码中的注释自动生成 api 文档,并且提供测试接口。
1.2 用法
- 引入依赖
<!-- swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
- 配置类SwaggerConfig.java
@Bean:交给spring管理
Docket:swagger2的核心对象
@Configuration
@EnableWebMvc
@EnableSwagger2
public class SwaggerConfig {
@Bean // 交给Spring管理
public Docket docket() {
// swagger2的核心对象
Docket docket = new Docket(DocumentationType.SWAGGER_2);
ApiInfo apiInfo = new ApiInfoBuilder()
.title("Java201 Api[接口文档]")
.description("项目1组文档")
.contact(new Contact("lxy","www.baidu.com","[email protected]"))
.version("1.0")
.build();
/**
* 配置docket
*/
docket.apiInfo(apiInfo)
.select()
// 配置类上面有@Api这个注解会被扫描到
.apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
// 配置方法上有@ApiOperation这个注解会被扫描到
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
//任何路径
.paths(PathSelectors.any())
.build();
return docket;
}
}
- spring-web.xml中配置
- 测试
过滤器放开路径/swagger-ui.html
controller下写个测试 SwaggerController:
@Controller
@Api(tags = "API测试",value = "测试类")
public class SwaggerController {
@GetMapping("/swagger/test")
@ResponseBody
@ApiOperation(tags = "测试方法",value = "xxxxxx")
@ApiImplicitParam(paramType = "query",name = "id",value = "数据id",required = true,dataType = "int")
public JsonResult test(Integer id){
return new JsonResult(200,"success",id);
}
@GetMapping("/swagger/test2")
@ResponseBody
@ApiOperation(tags = "测试方法2",value = "ooooo")
@ApiImplicitParams({
@ApiImplicitParam(paramType = "query",name = "id",value = "数据id",required = true,dataType = "int"),
@ApiImplicitParam(paramType = "query",name = "name",value = "名字",required = true,dataType = "string"),
})
public JsonResult test2(Integer id,String name){
return new JsonResult(200,"success",id+":"+name);
}
}
1.3 注解解释
@ApiImplicitParam参数:
2 JWT
2.1 简介
前后端完全分离:
找不到session
Json Web Token,是一种工具。格式为XXXX.XXXX.XXXX的字符串,以一种安全的方式在用户和服务器之间传递存放在JWT中的不敏感信息。
用户第二次不需要再次进行登陆操作,通过JWT可实现用户认证的功能。使用session,但会增加服务器存储压力,JWT将存储压力分布到各个客户端机器上,从而减轻服务器压力。
2.2 JWT的格式
由三个字符串组成:Header.Payload.Signature(Claim是描述Json的信息的一个Json,将Claim转码之后生成Payload)
Header 是由以下这个格式的 Json 通过 Base64 编码(编码不是加密,是可以通过反编码的方式获取到这个原来的 Json,所以 JWT 中存放的一般是不敏感的信息)生成的字符串,Header 中存放的内容是说明编码对象是一个 JWT 以及使用“SHA-256”的算法进行加密(加密用于生成 Signature)
Claim 是一个 Json,Claim 中存放的内容是 JWT 自身的标准属性,所有的标准属性都是可选的,可以自行添加,比如:JWT 的签发者、JWT 的接收者、JWT 的持续时间等;同时Claim 中也可以存放一些自定义的属性,这个自定义的属性就是在用户认证中用于标明用户身份的一个属性,比如用户存放在数据库中的 id,为了安全起见,一般不会将用户名及密码这类敏感的信息存放在 Claim 中。将 Claim 通过 Base64 转码之后生成的一串字符串称作 Payload。
Signature 是由 Header 和 Payload 组合而成,将 Header 和 Claim 这两个 Json 分别使用Base64 方式进行编码,生成字符串 Header 和 Payload,然后将 Header 和 Payload 以Header.Payload 的格式组合在一起形成一个字符串,然后使用上面定义好的加密算法和一个密匙(这个密匙存放在服务器上,用于进行验证)对这个字符串进行加密,形成一个新的字符串,这个字符串就是 Signature。
JWT大致流程:
2.3 认证原理
服务器在生成一个 JWT 之后会将这个 JWT 会以Authorization : Bearer JWT 键值对的形式存放在 cookies 里面发送到客户端机器,在客户端再次访问收到 JWT 保护的资源 URL 链接的时候,服务器会获取到 cookies 中存放的 JWT 信息,首先将 Header 进行反编码获取到加密的算法,在通过存放在服务器上的密匙对 Header.Payload 这个字符串进行加密,比对JWT 中的 Signature 和实际加密出来的结果是否一致,如果一致那么说明该 JWT 是合法有效的,认证成功,否则认证失败。
2.4 SSM整合JWT
- 导入依赖:java-jwt
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
依赖josn
- 前后端分离的JWT工具类
public class JwtUtil {
/**
* 加密密钥
*/
private static final String SECRET = "LXYgsagag";
/**
* 发行人
*/
private static final String ISSURE="lxy";
/**
* 存放用户id的key
*/
private static final String USERID = "userId";
/**
* 存放到jwt中 用户自定义数据的key(比如可以存放 登陆成功的整个用户对象/权限数据)
*/
private static final String DATA = "data";
/**
* 生存时间
*/
private static final Long EXPIRE_TIME = 60*1000L;
/**
* 生成token
* @param data : 存放的用户数据
* @param userId : 存放的用户id
* @param <T> : 数据类型
* @return
*/
public static<T> String sign(T data,Integer userId){
try {
// 指定加密算法
Algorithm algorithm = Algorithm.HMAC256(SECRET);
// 计算过期时间
Date expire = new Date(System.currentTimeMillis() + EXPIRE_TIME);
// 将用户对象转换成json字符串
ObjectMapper objectMapper = new ObjectMapper();
String jsonData = objectMapper.writeValueAsString(data);
// 生成token
return JWT.create()
.withClaim(USERID, userId)
.withClaim(DATA, jsonData)
.withExpiresAt(expire)
.withIssuer(ISSURE)
.sign(algorithm);
} catch (JsonProcessingException e) {
e.printStackTrace();
return null;
}
}
/**
* 验证token的正确性
* @param token : jwt token
* @param userId : 存放的用户id
* @return
*/
public static Boolean verify(String token , Integer userId){
try {
// 指定加密算法
Algorithm algorithm = Algorithm.HMAC256(SECRET);
// 验证器
JWTVerifier verifier = JWT.require(algorithm)
.withClaim(USERID, userId)
.withIssuer(ISSURE)
.build();
// 验证
verifier.verify(token);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 获取保存的用户id
* @param token
* @return
*/
public static Integer getUserId(String token){
try {
// 解码token
DecodedJWT decode = JWT.decode(token);
return decode.getClaim(USERID).asInt();
} catch (JWTDecodeException e) {
e.printStackTrace();
return null;
}
}
/**
* 获取用户保存的信息
* @param token : jwt token
* @param tClass : 存放数据的class对象
* @param <T> : 类型
* @return
*/
public static <T> T getData(String token,Class<T> tClass){
try {
// 解码token
DecodedJWT decode = JWT.decode(token);
// 存放的用户数据的json字符串
String jsonData = decode.getClaim(DATA).asString();
// 利用jackson将json转换成对象
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(jsonData, tClass);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
- 异常处理
JwtException.java
public class JwtException extends Exception {
private Integer code;
private String msg;
// 构造器,getter/setter方法
}
MyExceptionHandler.java
@ExceptionHandler(JwtException.class)
public JsonResult jwtExceptionHandler(JwtException e) {
return new JsonResult(e.getCode(),e.getMsg());
}
- 创建拦截器
AccessInterceptor
public class AccessInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 先从请求头里面去获取jwt token
String token = request.getHeader("Authorization");
// 验证是否为空
if (StringUtils.isEmpty(token)) {
throw new JwtException(6001,"token 为空!");
}
// 获取保存的用户信息
User user = JwtUtil.getData(token, User.class);
System.out.println(user);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}
JwtInterceptor.java
public class JwtInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 先从请求头里面去获取jwt token
String token = request.getHeader("Authorization");
// 验证是否为空
if (StringUtils.isEmpty(token)) {
throw new JwtException(6001,"token 为空!");
}
// 获取用户id
Integer userId = JwtUtil.getUserId(token);
if(userId == null){
throw new JwtException(6002,"token 不正确!请重新登陆!");
}
// 验证token
if (!JwtUtil.verify(token,userId)) {
throw new JwtException(6002,"token 不正确!请重新登陆!");
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}
- 控制层JwtController模拟登陆成功
@RestController
public class JwtController {
@Autowired
private UserMapper userMapper;
/**
* 登陆的方法
* @param userName
* @param pwd
* @return
*/
@PostMapping("/jwt/login")
public JsonResult login(String userName, String pwd){
// 模拟登陆成功
// 直接生成token
User dbUser = userMapper.findByName(userName);
String token = JwtUtil.sign(dbUser, 20);
return new JsonResult(200,"success",token);
}
@PostMapping("/jwt/list")
public JsonResult getList(){
return new JsonResult(200,"success");
}
}
- 在postman测试