• springboot+jwt实现token登陆权限认证


    一 前言

    此篇文章的内容也是学习不久,终于到周末有时间码一篇文章分享知识追寻者的粉丝们,学完本篇文章,读者将对token类的登陆认证流程有个全面的了解,可以动态搭建自己的登陆认证过程;对小项目而已是个轻量级的认证机制,符合开发需求;更多精彩原创内容关注公主号知识追寻者,读者的肯定,就是对作者的创作的最大支持

    二 jwt实现登陆认证流程

    • 用户使用账号和面发出post请求
    • 服务器接受到请求后使用私钥创建一个jwt,这边会生成token
    • 服务器返回这个jwt给浏览器
    • 浏览器需要将带有token的jwt放入请求头
    • 每次手到客户端请求,服务器验证该jwt的token
    • 验证成功返回响应的资源给浏览器。否则异常处理

    三 相关介绍jwt

    3.1jwt 组成

    JWT的token由三段信息构成的,将这三段信息文本用.连接一起就构成了JWT字符串;

    • Header 头部(包含了令牌的元数据,并且包含签名和或加密算法的类型)
    • Payload 负载
    • Signature 签名/签证
    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1ODI4OTc4NDUsInVzZXJuYW1lIjoienN6eHoifQ.vyiExkFWCCmQA3PFYL0jJfIiYGWubngqB0WcgmtHOxg
    

    3.2 jwt优点

    • 简洁(Compact): 可以通过URLPOST参数或者在HTTP header发送,数据量小,传输速度快
    • 自包含(Self-contained):负载中包含了所有用户所需要的信息,避免多次查询数据库
    • .因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言支持;
    • 不需要在服务端保存会话信息,适用于分布式与微服务;

    四 jwt用户登陆发放token

    4.1 pom.xml

    项目构件如下

    • springboot 2.1;
    • jwt 3.4.0;
    • maven 3.5
    • jdk1.8
    • postman接口测试
    <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>com.auth0</groupId>
                <artifactId>java-jwt</artifactId>
                <version>3.4.0</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
        </dependencies>
    

    4.2jwt工具类

    jwt工具类中有三个方法,分别是生成数字签名用于用户首次登陆时发送jwt给客户端;其次是校验方法,用于拦截器拦截所有规则内的url,每个请求都必须带有服务器发送的jwt,经过验证后才放行请求;最后一个获得用户名的方法用于查询密钥,在验证jwt时作为参数传入;

    /* *
     * @Author lsc
     * <p> JWT工具类 </p>
     * @Param
     * @Return
     */
    public class JwtUtil {
    
    	// Token过期时间30分钟
    	public static final long EXPIRE_TIME = 30 * 60 * 1000;
    
    	/* *
    	 * @Author lsc
    	 * <p> 校验token是否正确 </p>
    	 * @Param token
    	 * @Param username
    	 * @Param secret
    	 * @Return boolean
    	 */
    	public static boolean verify(String token, String username, String secret) {
    		try {
    			// 设置加密算法
    			Algorithm algorithm = Algorithm.HMAC256(secret);
    			JWTVerifier verifier = JWT.require(algorithm)
    					.withClaim("username", username)
    					.build();
    			// 效验TOKEN
    			DecodedJWT jwt = verifier.verify(token);
    			return true;
    		} catch (Exception exception) {
    			return false;
    		}
    	}
    
    
    
    	/* *
    	 * @Author lsc
    	 * <p>生成签名,30min后过期 </p>
    	 * @Param [username, secret]
    	 * @Return java.lang.String
    	 */
    	public static String sign(String username, String secret) {
    		Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
    		Algorithm algorithm = Algorithm.HMAC256(secret);
    		// 附带username信息
    		return JWT.create()
    				.withClaim("username", username)
    				.withExpiresAt(date)
    				.sign(algorithm);
    
    	}
    
    	/* *
    	 * @Author lsc
    	 * <p> 获得用户名 </p>
    	 * @Param [request]
    	 * @Return java.lang.String
    	 */
    	public static String getUserNameByToken(HttpServletRequest request)  {
    		String token = request.getHeader("token");
    		DecodedJWT jwt = JWT.decode(token);
    		return jwt.getClaim("username")
    				.asString();
    	}
    
    
    
    }
    
    

    4.3 用户实体

    实体中包含用户名,和密码,一切从简;

    /**
     * @Author lsc
     * <p> </p>
     */
    @Data
    public class SysUser {
    
        private String username;
    
        private String password;
    
    }
    
    

    4.4Controller

    表现层代码用户用户登陆认证,认证成功后发放token给客户端;

    /**
     * @Author lsc
     * <p> </p>
     */
    @RestController
    public class SysUserController {
    
        @PostMapping(value = "/login")
        public Map<String, Object> login(@RequestBody SysUser sysUser){
            Map<String, Object> map = new HashMap<>();
            String username = sysUser.getUsername();
            String password = sysUser.getPassword();
            // 省略 账号密码验证
            // 验证成功后发送token
            String token = JwtUtil.sign(username,password);
            if (token != null){
                map.put("code", "200");
                map.put("message","认证成功");
                map.put("token", token);
                return map;
            }
            map.put("code", "403");
            map.put("message","认证失败");
            return map;
        }
    }
    

    4.5 测试

    测试url http://localhost:8080/login

    postman post请求测试参数如下

    {
    	"username": "zszxz",
    	"password": "zszxz"
    }
    

    返回内容如下

    {
        "code": "200",
        "message": "认证成功",
        "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1ODI4OTc4NDUsInVzZXJuYW1lIjoienN6eHoifQ.vyiExkFWCCmQA3PFYL0jJfIiYGWubngqB0WcgmtHOxg"
    }
    

    五 jwt登陆拦截认证

    基于前面已经实现jwt登录认证后发放token给客户端;本节内容就是将token放入请求头中发送请求给服务器;服务器使用拦截器拦截请求对token进行验证;验证成功请求通过,否则请求资源失败;

    5.1自定义拦截器

    自定义拦截器JwtInterceptor,实现HandlerInterceptor接口,每次请求到达之前都会验证token是否有效;

    /**
     * @Author lsc
     * <p>token验证拦截器 </p>
     */
    @Component
    public class JwtInterceptor implements HandlerInterceptor {
    
        @Autowired
        SysUserService sysUserService;
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            // 从 http 请求头中取出 token
            String token = request.getHeader("token");
            // 如果不是映射到方法直接通过
            if(!(handler instanceof HandlerMethod)){
                return true;
            }
            if (token != null){
                String username = JwtUtil.getUserNameByToken(request);
                // 这边拿到的 用户名 应该去数据库查询获得密码,简略,步骤在service直接获取密码
                boolean result = JwtUtil.verify(token,username,sysUserService.getPassword());
                if(result){
                    System.out.println("通过拦截器");
                    return true;
                }
            }
            return false;
        }
    
        @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 {
    
        }
    }
    

    5.2 service

    /**
     * @Author lsc
     * <p> 模拟查询数据库获得账号密码 </p>
     */
    @Service
    public class SysUserService {
    
    
        public String getPassword(){
            return "zszxz";
        }
    }
    

    5.3拦截器配置

    拦截器配置中主要定义拦截请求规则,将拦截器注入WebMvcConfigurer;cors跨域处理;

    /* *
     * @Author lsc
     * <p>拦截器配置 </p>
     * @Param
     * @Return
     */
    @Configuration
    public class InterceptorConfig implements WebMvcConfigurer {
    
        /* *
         * @Author lsc
         * <p> 设置拦截路径 </p>
         * @Param [registry]
         * @Return void
         */
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(authenticationInterceptor())
                    .addPathPatterns("/**")
                    .excludePathPatterns("/login");
        }
        /* *
         * @Author lsc
         * <p> 将拦截器注入context </p>
         * @Param []
         * @Return com.zszxz.jwt.interceptor.JwtInterceptor
         */
        @Bean
        public JwtInterceptor authenticationInterceptor() {
            return new JwtInterceptor();
        }
    
        /* *
         * @Author lsc
         * <p>跨域支持 </p>
         * @Param [registry]
         * @Return void
         */
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**")
                    .allowedOrigins("*")
                    .allowCredentials(true)
                    .allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH", "OPTIONS", "HEAD")
                    .maxAge(3600 * 24);
        }
    }
    

    5.4Controller

    表现层接口用于拦截亲求测试

    /**
     * @Author lsc
     * <p> </p>
     */
    @RestController
    public class TestController {
    
        @GetMapping(value = "/api/test")
        public String get(){
    
            return "zszxz";
        }
    }
    

    5.5 测试

    测试url http://localhost:8080/api/test

    发送get请求给服务器,带有请求头,key为token,value为用户首次登陆时返回的token串;

    测试返回内容如下

    zszxz
    

    六 官网链接

    https://jwt.io/introduction/

    源码 关注公主号或者作者专栏说明即可获得;

  • 相关阅读:
    idea中如何配置tomcat
    onselectstart属性解决双击出现的蓝色区域
    (二十二)数组的最大值和最小值
    (二十一)数组的初始化
    (二十)两种数据类型的对比
    (十九)数组的内存分配
    (十八)数组概述
    (十六)函数的重载
    (十七)自定义函数
    (十五)函数的入栈和出栈
  • 原文地址:https://www.cnblogs.com/zszxz/p/12380618.html
Copyright © 2020-2023  润新知