• 项目总结67:Springboot中使用JWT+Token鉴权示例


    项目总结67:Springboot中使用JWT+Token鉴权示例

     START

    代码示例

      pom文件

            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt</artifactId>
                <version>0.7.0</version>
            </dependency>
            <dependency>
                <groupId>com.auth0</groupId>
                <artifactId>java-jwt</artifactId>
                <version>3.4.0</version>
            </dependency>

      JwtUtils类:创建JWT,解析JWT

    import io.jsonwebtoken.*;
    
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    import java.util.Base64;
    import java.util.Date;
    
    public class JwtUtils {
    
        public final static String JWT_KEY = "aaabbcccdd";
    
    
        //1-创建JWT
        public static String createJWT(String id, String subject, Long ttlMillis){
            Date now = new Date();
            Date expireDate = new Date(now.getTime()+ttlMillis);
            SecretKey secretKey = generateKey();
            JwtBuilder jwtBuilder = Jwts.builder()
                    .setHeaderParam("typ", "JWT")//
                    .setId(id)
                    .setSubject(subject)
                    .setIssuer("tangyujie")
                    .setIssuedAt(now)
                    .setExpiration(expireDate)
                    .signWith(SignatureAlgorithm.HS256, secretKey);
    
            //jwtBuilder.compact() = base64UrlEncodedHeader + '.' + base64UrlEncodedBody + '.' + base64UrlSignature;
            return jwtBuilder.compact();
        }
    
    
        //生成key
        private static SecretKey generateKey(){
            byte[] encodeKey = Base64.getDecoder().decode(JWT_KEY);
            return new SecretKeySpec(encodeKey,0,encodeKey.length,"AES");
        }
    
        //获取token中注册信息
        public static Claims getTokenClaim(String token){
            SecretKey secretKey = generateKey();
            try {
                return Jwts.parser()
                        .setSigningKey(secretKey)
                        .parseClaimsJws(token)
                        .getBody();
            } catch (Exception e) {
                return null;
            }
        }
    
        //验证token是否过期
        public static boolean isTokenExpired(Date expirationTime){
            return expirationTime.before(new Date());
        }
    }

       WebAppConfig: 实现WebMvcConfigurer接口,作拦截请求

    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;
    
    //WebMvcConfigurer是一个接口,提供很多自定义的拦截器,例如跨域设置、类型转化器等等
    @Configuration
    public class WebAppConfig implements WebMvcConfigurer {
    
    
        @Autowired
        private TokenInterceptor tokenInterceptor;
    
        //静态资源处理(这里是开放了Swagger组件的鉴权,因项目而异)
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("swagger-ui.html")
                    .addResourceLocations("classpath:/META-INF/resources/");
            registry.addResourceHandler("doc.html")
                    .addResourceLocations("classpath:/META-INF/resources/");
            registry.addResourceHandler("/webjars/**")
                    .addResourceLocations("classpath:/META-INF/resources/webjars/");
            registry.addResourceHandler("/swagger-resources/**")
                    .addResourceLocations("classpath:/META-INF/resources/swagger-resources/**");
            registry.addResourceHandler("/swagger/**")
                    .addResourceLocations("classpath:/META-INF/resources/swagger*");
            registry.addResourceHandler("/v2/**")
                    .addResourceLocations("classpath:/META-INF/resources/v2/**");
        }
    
    
        //拦截器:拦截或允许请求
        @Override
        public  void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(tokenInterceptor)
                    .addPathPatterns("/**")
                    .excludePathPatterns("/login")
                    .excludePathPatterns("/doc.html","/swagger-resources/**","/webjars/**","/v2/**","/swagger-ui.html","/","/error","/csrf","/favico*","/api-docs","swagger.json");
        }
    }

      TokenInterceptor类:拦截器

    import io.jsonwebtoken.Claims;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.lang.Nullable;
    import org.springframework.stereotype.Component;
    import org.springframework.util.StringUtils;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.security.SignatureException;
    
    @Component
    public class TokenInterceptor extends HandlerInterceptorAdapter {
    
        private final Logger logger = LoggerFactory.getLogger(TokenInterceptor.class);
    
    
    
        //在方法被调用前执行。
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            logger.info("request start urL:{}",request.getRequestURL());
            String token = request.getHeader("Authorization");//从header中获取Authorization
            //重新登陆判断
            if(StringUtils.isEmpty(token)){
                throw new SignatureException("登陆信息为空,或者失效,请重新登陆");
            }
            Claims claims = JwtUtils.getTokenClaim(token);//从token中解析出Claims
            if(claims == null){
                throw new SignatureException("登陆信息为空,或者失效,请重新登陆");
            }
            if(JwtUtils.isTokenExpired(claims.getExpiration())){
                throw new SignatureException("登陆信息过期,请重新登陆");
            }
            String account = claims.getSubject();//从claims中获取subject
            request.setAttribute("account",account);//将数据放在request中
            return true;
        }
    
        //在方法执行后调用
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                               @Nullable ModelAndView modelAndView) throws Exception {
            logger.info("request over  uri:{}",request.getRequestURI());
        }
    
    
    }

      controller类:模拟接口请求

    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.UUID;
    
    /***
    *@description
    *@author viruser
    *@date 2020/9/8 20:04
    */
    @RestController
    @RequestMapping("")
    public class LoginController {
    
        //1-登陆(认证+生成token)
        @GetMapping("/login")
        public Object login(
                @RequestParam String account,
                @RequestParam String password,
                HttpServletResponse response){
            //1- 根据帐号密码请求数据库,获取用户信息
            //......模拟用户,将account放进accessToken中
            //2- 生成jwt
            String accessToken = JwtUtils.createJWT(UUID.randomUUID().toString(), account, 7200000L);
            //3-在header中返回accessToken
            response.setHeader("accessToken",accessToken);
            return "success and accessToken: " + accessToken;
        }
    
    
        //2-查询(示例如何获取请求域中的数据)
        @GetMapping("/user")
        public String getUserInfo(HttpServletRequest request){
            String account = String.valueOf(request.getAttribute("account"));////从request中取出数据
            return "account: " + account;
        }
    
    
    }

    END

  • 相关阅读:
    关于多个EditText的OnTextChange事件陷入死循环的处理
    #define #include #undef的其中一个用法(目的)
    串行移位锁存并行输出可级联器件74HC595
    STM32F10xx CAN BUS相关库文件"stm32f10x_can.c"内的库函数解析
    STM32 之 NVIC(中断向量、优先级) 简述
    STM32F103xx bxCAN(Basic Extended CAN) 滤波机制
    VS上利用C#实现一个简单的串口程序记录
    如何去各型MCU的官网上下载正确的数据手册
    Cotex-M3内核STM32F10XX系列时钟及其配置方法
    Stm32 debug停留在"BKPT 0xAB"或者"SWI 0xAB"的解决办法。
  • 原文地址:https://www.cnblogs.com/wobuchifanqie/p/13641601.html
Copyright © 2020-2023  润新知