分类:
Java
文章借鉴于://https://www.jianshu.com/p/6e5ee9dd5a61
一、pom的相关依赖
<!--版本控制2.5.5--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.5</version> <!--版本控制2.5.5--> <relativePath/> </parent> <!--web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!--swagger--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <!--JWT--> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.10.0</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.0</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.9</version> </dependency>
二、swagger 的配置
导入相关的包
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.PathSelectors; 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.List;
@Configuration
@EnableSwagger2
public class SwaggerConfig2 { //https://www.jianshu.com/p/6e5ee9dd5a61
@Bean
public Docket api(){
return new Docket(DocumentationType.SWAGGER_2).
useDefaultResponseMessages(false)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.regex("^(?!auth).*$"))
.build()
.securitySchemes(securitySchemes())
.securityContexts(securityContexts());//
}
private List<ApiKey> securitySchemes()
{
return newArrayList( new ApiKey("Authorization", "Authorization","header"));
}
private List<SecurityContext> securityContexts() {
return newArrayList(
SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.regex("^(?!auth).*$"))//含有auth路径的接口可以没有令牌
.build()
);
}
List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
return newArrayList(
new SecurityReference("Authorization", authorizationScopes));
}
}1、配完后会出现这个

2、下图是这个按钮的内容
三、配置toke令牌的加密、解密
1、类Constant的字段设置
public final static String TOKEN_HEADER_STRING="Authorization"; public final static String TOKEN_PERFIX="Bearer"; public final static String CURRENT_USER="name"; public final static String BASE_PATH_PERFIX="/api/practice/v1";
2、toke的配置

导入的包
import com.example.My1101.pojo.Constant; import io.jsonwebtoken.Claims; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.apache.commons.codec.binary.Base64; import org.springframework.stereotype.Component; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.util.Calendar; import java.util.Date; import java.util.HashMap;
//SpringBoot中组件类需要使用@Component进行组件注册才能使用(不知道该类属于什么层就可以用它,如:服务处、Dao等)
@Component
public class TokenUtils {
/**
* 由字符串生成加密key
* @return
*/
public static SecretKey generalKey() {
String stringKey = "thisisasecretkey"; //随机写的
// 本地的密码解码
byte[] encodedKey = Base64.decodeBase64(stringKey);
// 根据给定的字节数组使用AES加密算法构造一个密钥
SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
return key;
}
/**
* 生成JWT
* @return
*/
public static String createToken(String userName) {
//设置JWT的header
HashMap<String, Object> map = new HashMap<String, Object>();
//Head
map.put("alg", "HS256");
map.put("typ", "jwt");
//Payload
map.put("username", userName); //根据userName生成jwt
//设置JWT的过期时间
Calendar now = Calendar.getInstance();
now.add(Calendar.MINUTE, 20);//当前时间+20mins
Date expireDate = now.getTime();//Calendar转Date
//设置JWT生效时间
Date nowDate = new Date();//系统当前时间
SecretKey key = generalKey(); //密钥(服务端专有,面向客户端隐藏)
JwtBuilder jwtBuilder = Jwts.builder()
.setClaims(map)
.setExpiration(expireDate)
.setNotBefore(nowDate)
//Signature
.signWith(SignatureAlgorithm.HS256, key);//设置签发算法和密钥
return Constant.TOKEN_PERFIX + jwtBuilder.compact();//jwt前面一般会加上Bearer
}
/**
* 解析token
* @param token
* @return
*/
public static Claims parseToken(String token) {
SecretKey key = generalKey();
try {
Claims claims = Jwts.parser()
.setSigningKey(key)
.parseClaimsJws(token.replace("Bearer", "")).getBody();//TOKEN_PERFIX = "Bearer"
return claims;
} catch (Exception e) {
throw new IllegalStateException("Invalid token." + e.getMessage());
}
}
}四、拦截的具体逻辑
导入的包
import com.example.My1101.pojo.Constant; import io.jsonwebtoken.Claims; import io.swagger.models.HttpMethod; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Date;
@Component //拦截器也是一个组件,需要加@Component注解进行组件注册
public class AuthInterceptor implements HandlerInterceptor {
//声明一个static final的Logger对象
private static final Logger logger = LoggerFactory.getLogger(AuthInterceptor.class);
/**
* 预处理回调方法,实现处理器的预处理
* 返回值:true表示继续流程;false表示流程中断,不会继续调用其他的拦截器或处理器
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// return HandlerInterceptor.super.preHandle(request, response, handler);
System.out.println("开始拦截.........");
//设置response的编码格式
response.setContentType("text/html;charset=utf-8");
//获取请求的url
String url = request.getServletPath().toString();
System.out.println("url:" + url);
//判断放行的url
if(url.contains("/user/login")){
return true;
}
if(url.contains("/user/test2")){
return true;
}
if(url.contains("/swagger-resource")){
return true;
}
if(url.contains("/v2/api-docs")){
return true;
}
//第一次请求放行(因为它是探路用的)
if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
System.out.println("OPTIONS请求,放行");
return true;
}
//获取request中的参数token
String token = request.getHeader(Constant.TOKEN_HEADER_STRING);
//如果token为空或不存在
if(token==null || "".equals(token) || !token.startsWith(Constant.TOKEN_PERFIX)){
logger.info("{} : Unknown token", request.getServletPath());
//将结果打印返回到前端
response.getWriter().print("The resource requires authentication, which was not supplied with the request");
return false;//拦截成功
}
//解析token
Claims claims = TokenUtils.parseToken(token);
String userName = (String)claims.get("username");
Date expireTime = claims.getExpiration();
//如果token的username不存在 ,具体的逻辑自己发挥
if(userName.equals(null)){
logger.info("{} : token user not found", request.getServletPath());
response.getWriter().print("ERROR Permission denied");
return false;
}
//如果token过期
if(expireTime.before(new Date())){
logger.info("{} : token expired", request.getServletPath());
response.getWriter().print("The token expired, please apply for a new one");
return false;
}
//token匹配成功,放行
request.setAttribute(Constant.CURRENT_USER, userName);
System.out.println("放行...........");
return true;
}
/**
* 后处理回调方法,实现处理器(controller)的后处理,但在渲染视图之前
* 此时我们可以通过modelAndView对模型数据进行处理或对视图进行处理
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
/**
* 整个请求处理完毕回调方法,即在视图渲染完毕时回调,
* 如性能监控中我们可以在此记录结束时间并输出消耗时间,
* 还可以进行一些资源清理,类似于try-catch-finally中的finally,
* 但仅调用处理器执行链中
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}五、配置mvc 实现拦截
导入的包
import com.example.My1101.pojo.Constant; import com.example.My1101.utils.AuthInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
AuthInterceptor authInterceptor;
/**
* 添加拦截器
* addPathPatterns 用于添加拦截规则,/**表示拦截所有请求
* excludePathPatterns 排除拦截
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册AuthInterceptor拦截器
registry.addInterceptor(authInterceptor).addPathPatterns(Constant.BASE_PATH_PERFIX +"/**") //拦截/api/practice/v1/user/test
.excludePathPatterns(Constant.BASE_PATH_PERFIX + "/user/login"); //放行/api/practice/v1/user/login
}
// 这个方法是用来配置静态资源的,比如html,js,css,等等
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
}
}六、controller层的应用
@Api("用户操作接口")
@RestController("user")
@RequestMapping("/api/practice/v1" + "/user") //配置网址前缀 BASE_PATH_PERFIX = "/api/practice/v1"
public class UserController {
@Autowired
UserService userService;
@ApiOperation(value = "登录", notes = "通过用户名和密码登录系统") //配置方法操作在swagger中的名和曾 notes为备注
@PostMapping(value = "login")
public String login(@RequestBody User user) {
if (user == null) {
return "用户名或密码为空!";
}
User loginUser = userService.login(user);
if (loginUser == null) {
return "用户名或密码错误!";
}
//生成token(用户拿着这个token+请求返回给服务端,服务端匹配token,如果匹配上了则处理用户发来的请求,如果匹配不上则用户验证失败不处理请求)
String jwt = TokenUtils.createToken(user.getUserName());
HashMap<String, String> map = new HashMap<>();
map.put("token", jwt);
return ResponseEntity.ok("loginUser").toString() + map;
}
@ApiOperation(value = "测试", notes = "通过用户名和密码测试token")
@PostMapping(value = "test/{toke}")
public String testToken(User user,String toke){
return user.toString();
}
@ApiOperation(value = "测试2", notes = "通过用户名和密码测试token")
@PostMapping(value = "test2")
public String testToken2(User user){
return user.toString();
}
}评价
排名
6
文章
6
粉丝
16
评论
8
{{item.articleTitle}}
{{item.blogName}} : {{item.content}}
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:
50010702506256
50010702506256
欢迎加群交流技术