
文章借鉴于://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();
- }
- }
评价
排名
4
文章
473
粉丝
3
评论
2
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:
50010702506256


欢迎加群交流技术