jwtdemo 实现

一、添加依赖

<dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.10.2</version>
</dependency>

二、jwt配置(写在yml文件里即可)

jwt:
  secret: 6913cbb4bbfc53feb70b06ed00cd47ea
  ## 过期时间 单位分钟,整数
  exp: 1440

 

三、utils

1.JwtProperties  读取yml配置文件

@Component
@ConfigurationProperties(prefix = "jwt")
@Data
public class JwtProperties {
    /**
     * 密钥
     */
    private String secret;

    /**
     * 过期时间,单位为分钟
     */
    private Integer exp;
}

2.TokenUser用户信息封装类,可根据自己的业务类型去定义


@Data
public class TokenUser {
    /**
     * 用户ID存到token中
     */
    String id;

    /**
     * 用户openid
     */
    String openId;

    /**
     * 团长id
     */
    String leaderId;
}

3.PassToken 注解,用于不校验token的方法

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {
    boolean required() default true;
}

4.TokenService 及其实现

public interface TokenService {
    String getToken(TokenUser user);
}
@Service
public class TokenServiceImpl implements TokenService {
    private final JwtProperties jwtProperties;

    public TokenServiceImpl(JwtProperties jwtProperties) {
        this.jwtProperties = jwtProperties;
    }

    @Override
    public String getToken(TokenUser user) {
        JWTCreator.Builder builder = JWT.create();
        //withAudience()存入需要保存在token的信息,这里我把用户id和openId存入token中
        builder.withAudience(JSONObject.toJSONString(user));
        //添加Token过期时间
        long expMillis = System.currentTimeMillis() + Long.valueOf(jwtProperties.getExp()*60*1000);
        Date exp = new Date(expMillis);
        builder.withExpiresAt(exp);
        return builder.sign(Algorithm.HMAC256(jwtProperties.getSecret()));
    }
}

四、controller,获取token,UserService需替换成自己的业务接口

@RestController
public class TokenController extends BaseController {

    private final TokenService tokenService;

    private final UserService userService;

    public TokenController(TokenService tokenService, UserService userService) {
        this.tokenService = tokenService;
        this.userService = userService;
    }

    @ApiOperation("微信用户获取token")
    @PassToken
    @PostMapping("/wx/token")
    public ResponseEntity getToken(@RequestBody GetTokenQuery tokenQuery) {
        //查询微信用户表Id
        WechatUser userWx = null;
        if(StringUtils.isNotBlank(tokenQuery.getOpenId())){
            userWx = userService.findUserByOpenid(tokenQuery.getOpenId());
        }else if(StringUtils.isNotBlank(tokenQuery.getMobile())){
            //手机号不为空,解密手机号,去获取微信用户表信息
            byte[] mobileByte = Base64.getDecoder().decode(tokenQuery.getMobile());
            userWx = userService.findUserByMobile(new String(mobileByte));
        }
        if(userWx != null){
            TokenUser tokenUser = new TokenUser();
            tokenUser.setId(userWx.getUserId());
            tokenUser.setOpenId(userWx.getSmallOpenId());
            return new ResponseEntity<>(new ResponseResult<>(HttpStatus.OK.value(),
                    tokenService.getToken(tokenUser),
                    "获取token成功"),
                    HttpStatus.OK);
        }else{
            return new ResponseEntity<>(new ResponseResult<>(ServiceException.Problems.EXCEPTION.getCode(),
                    null,
                    "获取token失败"),
                    HttpStatus.OK);
        }
    }
}

五.拦截器

1.添加拦截器,WechatUserMapper需替换成自己的业务接口

public class AuthenticationInterceptor implements HandlerInterceptor {

    private Logger logger = LoggerFactory.getLogger(AuthenticationInterceptor.class);

    @Autowired
    private WechatUserMapper wechatUserMapper;

    @Autowired
    private JwtProperties jwtProperties;

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
        //拒绝频繁请求
        String ip = httpServletRequest.getRemoteAddr();
        String url = httpServletRequest.getRequestURL().toString();
        if(url.contains("swagger")) return true;

        //验证token
        String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token
        // 如果不是映射到方法直接通过
        if(!(object instanceof HandlerMethod)){
            return true;
        }
        HandlerMethod handlerMethod=(HandlerMethod)object;
        Method method=handlerMethod.getMethod();
        //检查是否有passtoken注释,有则跳过认证
        if (method.isAnnotationPresent(PassToken.class)) {
            PassToken passToken = method.getAnnotation(PassToken.class);
            if (passToken.required()) {
                return true;
            }
        }
        // 执行认证
        if (token == null) {
            throw new ServiceException(
                    ServiceException.Problems.SMALL_LOGIN_AUTHORIZE_FAIL_EXCEPTION.getCode(),
                    "无token,请重新授权");
        }
        // 获取 token 中的 user id
        TokenUser tokenUser;
        try {
             tokenUser = JSONObject.parseObject(
                    JWT.decode(token).getAudience().get(0),
                    TokenUser.class);
        } catch (JWTDecodeException e) {
            logger.error("解析userId失败" + e.getMessage());
            throw new ServiceException(
                    ServiceException.Problems.SMALL_LOGIN_AUTHORIZE_FAIL_EXCEPTION.getCode(),
                    "认证失败,请重新授权");
        }
        WechatUser user = wechatUserMapper.selectByPrimaryKey(tokenUser.getId());
        if (user == null) {
            throw new ServiceException(
                    ServiceException.Problems.SMALL_LOGIN_AUTHORIZE_FAIL_EXCEPTION.getCode(),
                    "用户不存在,请重新授权");
        }
        // 验证 token
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(jwtProperties.getSecret())).build();
        try {
            jwtVerifier.verify(token);
        } catch (JWTVerificationException e) {
            logger.error("校验token失败" + e.getMessage());
            throw new ServiceException(
                    ServiceException.Problems.SMALL_LOGIN_AUTHORIZE_FAIL_EXCEPTION.getCode(),
                    "授权超过有效时间,请重新授权");
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest,
                           HttpServletResponse httpServletResponse,
                           Object o, ModelAndView modelAndView) throws Exception {

    }
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest,
                                HttpServletResponse httpServletResponse,
                                Object o, Exception e) throws Exception {
    }
}

2.配置拦截器

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authenticationInterceptor())
                .addPathPatterns("/**");
    }
    @Bean
    public AuthenticationInterceptor authenticationInterceptor() {
        return new AuthenticationInterceptor();
    }
}

完毕 !

posted @ 2020-09-01 15:29  KyleCool  阅读(389)  评论(0)    收藏  举报