目录

目录

1.概述

2. 实现步骤

        2.1 maven引入相关包

        2.2 建立辅助类

        2.3 定义拦截器

        2.4 controller编写

        2.5 注册拦截器

3. 测试验证

        3.1 不登录,直接调用getUserList请求

         3.2 登录获取token值

        3.3 再来调用getUserList

4. 结语

1.概述

        经常写http、https请求的程序开发,经常碰到三方都有一个token(令牌)的授权与验证,感觉这个功能很好用,借此学习SpingBoot的机会,在网上去找了一篇相关的文章,进行实际操作下。我原本以为token是生成后会保存到数据库去,其实不然,可能场景不同,实际也会有点差别。

        22年底时候,当时对接社会化信息、公安信息、实名就诊信息等接口时候,都用到了这个。通过注册或服务直接分配,得到一个账号。通过授权(登录)获得一个token,这个token是有时间限制的,比如2个小时,然后才可以调用服务的接口。2个小时后,需要重新授权(登录)。

2. 实现步骤

        2.1 maven引入相关包

        在pom.xml文件,加入依赖。

<!-- jwt生成token的库 -->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.10.3</version>
        </dependency>

        2.2 建立辅助类

        这个辅助类提供token生成与验证功能。额外写一个test()方法,加入了@Test注解,进行单元测试操作。

public class JwtUtils {

    public static String SECRET= "1c2h3e4n5w6e7i8x9i0n";

    public static String getToken(Map<String, String> map){
        JWTCreator.Builder builder= JWT.create();
        map.forEach((k,v)->{
            builder.withClaim(k,v);
        });
        Calendar instance= Calendar.getInstance();
        instance.add(Calendar.HOUR, 2);  //默认2小时过期

        builder.withExpiresAt(instance.getTime());
        String token= builder.sign(Algorithm.HMAC256(SECRET));
        return token;
    }

    public static DecodedJWT verfy(String token){
        DecodedJWT decodedJWT= JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token);
        return decodedJWT;
    }

    @Test
    public void test() {
        Map<String,String> map=new HashMap<>();
        map.put("username", "1107230602");
        map.put("password", "0246813579");
        String token= JwtUtils.getToken(map);
    }
}

        2.3 定义拦截器

        拦截器的作用主要是完成请求参数的解析、将页面表单参数赋给值栈中相应属性、执行功能检验、程序异常调试等工作。此处拦截的功能是对token进行校验.

@Slf4j
public class JwtInterceptor implements HandlerInterceptor {


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token= request.getHeader("token");
        Map<String, Object> map= new HashMap<>();
        if (token== null || token.trim().equals("")){
            map.put("message", "无token值!");
        } else{
            try{
                JwtUtils.verfy(token);
                return true;
            } catch (SignatureVerificationException e){
                e.printStackTrace();
                map.put("message", "签名不一致!");
            } catch (TokenExpiredException e){
                e.printStackTrace();
                map.put("message","令牌过期!");
            } catch (AlgorithmMismatchException e){
                e.printStackTrace();
                map.put("message", "算法不匹配!");
            } catch (InvalidClaimException e){
                e.printStackTrace();
                map.put("message","失效payload!");
            } catch (Exception e){
                e.printStackTrace();
                map.put("message","token无效");
            }
        }
        map.put("state", false);
        String json= new ObjectMapper().writeValueAsString(map);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(json);
        return false;
    }
}

        2.4 controller编写

        我在UserController中添加了一个获取用户列表、登录两个功能。在登录方法中,实现token的获取并返回。该方法仅仅用于举例说明。在这个controller的类抬头,我还加入了@RequestMapping,所以,接口调用地址是".../api/user/getUserList"和".../api/user/login"

@RequestMapping("/api")
/**
     * 查询所有数据
     * @return
     */
    @GetMapping("/user/getUserList")
    public Result<?> getUserList(){
        List<User> userList= null;
        SqlSession sqlSession= null;
        try{
            sqlSession= MybatisUtils.getSqlSession();
            //Mapper代理开发
            UserMapper mapper= sqlSession.getMapper(UserMapper.class);
            userList= mapper.getUserList();
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (sqlSession!= null) {
                sqlSession.close();
            }
        }
        return Result.ok(userList);
    }

    /**
     * 登录验证
     * @return
     */
    @PostMapping("/user/login")
    public Result<?> login(@RequestBody User user){
        SqlSession sqlSession= null;
        Map<String, Object> map= new HashMap<>();
        try{
            sqlSession= MybatisUtils.getSqlSession();
            UserMapper mapper= sqlSession.getMapper(UserMapper.class);
            user= mapper.login(user);
            if (user!= null){
                //生成token
                Map<String, String> tokenmap= new HashMap<>();
                tokenmap.put("username", user.getUsername());
                tokenmap.put("password", user.getPassword());
                String token= JwtUtils.getToken(tokenmap);
                //返回数据
                map.put("user", user);
                map.put("token", token);
                return Result.ok(map);
            } else {
                return Result.error(CommonConstant.SYS_ERR_CODE, "用户不存在!");
            }
        } catch (Exception e){
            e.printStackTrace();
            return Result.error("异常!"+ e.getMessage());
        } finally {
            if (sqlSession!= null){
                sqlSession.close();
            }
        }
    }

        2.5 注册拦截器

        在2.3中定义了拦截器,通过注册,启动拦截器功能。addPathPatterns()方法是只将哪些api纳入拦截范围。excludePathPatterns()方法是排除哪些,二者功能相反。像登录操作,肯定是不需要进行token验证的,就排除在外了。

@Configuration
public class JwtInterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new JwtInterceptor())
                .addPathPatterns("/api/user/**")
                .excludePathPatterns("/api/user/login");
    }
}

3. 测试验证

        3.1 不登录,直接调用getUserList请求

        

Spring Boot发布鉴权接口 springboot token鉴权_java

         3.2 登录获取token值

        

Spring Boot发布鉴权接口 springboot token鉴权_token_02

        3.3 再来调用getUserList

        

Spring Boot发布鉴权接口 springboot token鉴权_java_03

4. 结语

        token的授权和验证,在web服务中是一种很常见的用法。