登录
原创

Java自定义注解(三)

专栏Java自定义注解
发布于 2021-03-04 阅读 683
  • Java
原创

前面介绍了如何获取注解的值,那么本篇将介绍如何真正的在实际的业务中去使用()自定义注解,并且结合JWT组件来实现用户信息的通过注解的方式来获取

JWT工具类

package com.example.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.util.DigestUtils;

import java.util.Date;
import java.util.HashMap;

public class JwtUtils {
    //需要的过期时间
    public final static long EXPIRE_TIME = 60 * 1000;
    //需要的生成密钥,防止token伪造
    public final static String TOKEN_SECRET = "5d41402abc4b2a76b9719d911017c592";


    /**
     * 根据用户id生成token
     *
     * @param id 用户id
     * @return
     */
    public static String generateToken(String id) {
        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
        //使用hash算法
        Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
        HashMap<String, Object> header = new HashMap<>();
        header.put("type", "JWT");
        header.put("alg", "HMAC256");
        String token = JWT.create().withHeader(header).withExpiresAt(date).withClaim("id", id).sign(algorithm);
        return token;
    }


    /**
     * 验证token是否是服务器颁发的
     *
     * @param token 用户传过来的token参数
     * @return
     */
    public static boolean verifyToken(String token) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            JWTVerifier build = JWT.require(algorithm).build();
            build.verify(token);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 从token中取出负载,即JWT create的时候加入的claim
     *
     * @param token
     * @return
     */
    public static String getClaim(String token) {
        DecodedJWT decode = JWT.decode(token);
        Claim id = decode.getClaim("id");
        return id.asString();
    }

    public static void main(String[] args) {

        //生成一个token
        System.out.println(generateTokenSecret());
        //根据用户id生成一个token
        String token = generateToken("10");
        //校验token
        verifyToken(token);
        //获取token中的负载,也就是当时传入进去的值
        System.out.println(getClaim(token));
    }

    /**
     * 用md5生成一个密钥
     *
     * @return
     */
    public static String generateTokenSecret() {
        return DigestUtils.md5DigestAsHex("hello".getBytes());
    }
}

自定义注解

package com.example.annotaion;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserId {
}

使用HandlerMethodArgumentResolver

在resolver里面来处理校验token逻辑,同时根据用户传参数信息,通过自己到校验逻辑,封装用户信息到自定义注解里面的参数里

package com.example.resolver;

import com.example.annotaion.UserId;
import com.example.util.JwtUtils;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

public class UserIdHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType().isAssignableFrom(String.class)
                && parameter.hasParameterAnnotation(UserId.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        String token = webRequest.getParameter("token");
        boolean b = JwtUtils.verifyToken(token);
        if (b) {
            return JwtUtils.getClaim(token);
        }
        return null;
    }
}

注册参数解析器

import com.example.interceptor.AuthenticationInterceptor;
import com.example.resolver.UserIdHandlerMethodArgumentResolver;
import com.example.resolver.UserInfoArgumentResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

//配置拦截器
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {

// resolvers.add(new UserInfoArgumentResolver());
resolvers.add(new UserIdHandlerMethodArgumentResolver());
}

}

controller里面的使用

package com.example.controller;

import com.example.annotaion.CacheResult;
import com.example.annotaion.KeyVerify;
import com.example.annotaion.LoginUserInfo;
import com.example.annotaion.UserId;
import com.example.entity.LoginUser;
import com.example.util.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
@CacheResult(key = "class_key", cacheName = "class_cacheName")
@Slf4j
public class TestController {


    /**
     * 模拟用户登录,登录成功后返回给用户一个token
     * @param userid
     * @return
     */
    @RequestMapping("/login")
    public Map select(@UserId String userid) {
        HashMap<String, Object> map = new HashMap<>();
        log.info("用户认证通过,id是:{}", userid);
        map.put("code", 200);
        String oid = "10";
        map.put("token", JwtUtils.generateToken(oid));
        return map;
    }

    /**
     * 用户拿着token来付款,此时参数中没有用户的id信息,但是可以通过解析器里面的token来获取
     * @param id
     * @param token
     */
    @RequestMapping("pay")
    public String pay(@UserId String id, String token) {
        log.info("id:{}", id);
        return id;
    }
}

login方法模拟用户登录,用户登录成功之后,返回一个token给用户,当用户下次访问付款接口当时候,传统的从session中获取用户信息的伪代码如下


    @RequestMapping("/pay2")
    public void pay(HttpServletRequest request) {
        HttpSession session = request.getSession();
        User user = (User)session.getAttribute("user-info");
        String token = request.getParameter("token");
        boolean b = JwtUtils.verifyToken(token);
        if (b){
            String id = JwtUtils.getClaim(token);
            log.info("id:{}", id);

        }
    }

但是通过使用解析器以及自定义注解,我们成功得将校验逻辑和业务分离了,整个controller里面变得清洁了

请求测试

登录服务器

http://localhost:8080/login
image.png

付款请求

http://localhost:8080/pay?token=eyJ0eXBlIjoiSldUIiwiYWxnIjoiSFMyNTYiLCJ0eXAiOiJKV1QifQ.eyJpZCI6IjEwIiwiZXhwIjoxNjE0ODQ2MTExfQ.CA6ehO1Z13sQZ3TE_QYJCnxUKg2xffKcSNOprNZaL8s
image.png

控制台输出

2021-03-04 16:20:51.216  INFO 15612 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-03-04 16:20:51.216  INFO 15612 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2021-03-04 16:20:51.220  INFO 15612 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 4 ms
2021-03-04 16:20:51.243  INFO 15612 --- [nio-8080-exec-1] com.example.controller.TestController    : 用户认证通过,id是:null
2021-03-04 16:21:05.735  INFO 15612 --- [nio-8080-exec-2] com.example.controller.TestController    : id:10

评论区

眉上的汗水,眉下的泪水,你总要选择一样

0

0

0

举报