说在前面
用自己的依赖真的很酷!
想了很久还是决定自己写一个JWT的工具类。虽然目前常用的像hutools、sa-token等我都十分满意、也十分敬佩开发者的技术与想法,但对于简单项目来说使用体验都并不“简单”。对我而言,通过注解标记载荷中的字段并使用.yml文件配置签名和过期时间才是理想型,不需要太多功能,也不需要过分的个性化,简单地注入依赖即可生成、校验、解析token才最合适。
编写工具类
首先在Idea中创建一个maven工程,类型随便即可(清除所有自动生成,保留原生maven工程即可),其中pom.xml文件内容如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
接下来开始编码,创建一个注解类@Token
(当然你也可以叫@Feild
或者其他更合适的称谓):
package com.steadon;
import java.lang.annotation.*;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Token {
String value() default "";
}
解释一下用到的元注解:
@Target(ElementType.FIELD)
:靶注解,表示自定义注解应该使用在自动上。@Retention(RetentionPolicy.RUNTIME)
:保留注解,表示自定义注解保留到程序运行时。@Inherited
:继承注解,表示被该注解可以随字段继承而继承。
那么此时这个注解已经可以读取标记字段的字段名了,但是想要通过字段名获取属性还需要使用Java的反射来实现,接下来编写工具类:
/**
* A lightweight tool for generating tokens quickly
*
* @author Steadon
* @version 1.2.0
*/
@Component
public class JWTUtils {
private String sign;
private String time;
private int _time;
public JWTUtils() {}
public String getSign() {return sign;}
public void setSign(String sign) {this.sign = sign;}
public String getTime() {return time;}
public void setTime(String time) {
this.time = time;
this._time = Integer.parseInt(time);
}
......
}
通过以上代码我们向SpringBoot注册了一个Bean(即属性私有,所有属性都应该有setter和getter方法,并且含有一个无参构造器),其中sign和time是要从配置文件中读取内容的,为了保证time后期的扩展性我们使用String类型,并在类的内部转为整型。
/**
* The default way is to create a token string
* The target field is automatically identified based on the incoming object with @Token annotation field
* And read the signature and expiration _time in the configuration file to generate a token
*
* @param t The object to which the payload field belongs
* @param <T> Any type
* @return The token string that is created
*/
public <T> String createToken(T t) {
ObjectMapper objectMapper = new ObjectMapper();
JWTCreator.Builder builder = JWT.create();
Field[] declaredFields = t.getClass().getDeclaredFields();
for (Field field : declaredFields) {
if (field.isAnnotationPresent(Token.class)) {
field.setAccessible(true);
Object o = null;
try {
o = field.get(t);
builder.withClaim(field.getName(), objectMapper.writeValueAsString(o));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Calendar instance = Calendar.getInstance();
instance.add(Calendar.SECOND, this._time);
return builder.withExpiresAt(instance.getTime()).sign(Algorithm.HMAC256(this.sign));
}
这段代码实现了创建token字符串的功能,该方法获取传入对象的class对象中获取其对应类型的所有字段,并依次检查是否存在@Token
注解,发现标记字段后将其设为可见(避免private修饰导致无法读取字段),随后使用field.get(t)
方法获取对象中该字段的具体值,并由builder将其放入载荷。所有标记字段的值都放入载荷之后,加上过期时间和签名生成最终token并返回。
最后我们加上读取配置文件的需要的注解和配置文件:
#src/main/resources/META-INF/spring.factories (工具类在SpringBoot中的可被发现)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.steadon.JWTUtils
@Component
@ConfigurationProperties(prefix = "token") //将配置文件中token前缀的字段映射到类的属性
public class JWTUtils {...}
(其他方法例如解析和校验便不再展示,详情请见github.com/steadon/JWT…)
添加开源协议
想要将jar包上传到中央仓库就必须得开源,这里演示一下github上的开源流程:
接下来自己选择开源协议即可(略),笔者用的是Apache - 2.0 license
,如果是第一次开源建议和笔者一致。
发布GPG公钥
gpg其实就是一个非对称加密工具,需要借助工具生成公钥和私钥,并将公钥放发布到中央用于别人对你的项目进行验证。
- mac : 下载GPG Suite,后续无脑操作。
- win/linux : 下载GnuPG,后续可采用命令行操作。
- 生成 :
gpg --gen-key
- 查看 :
gpg --list-keys
- 上传 : (自己想办法吧)
- 生成 :
申请Maven仓库
接下来申请maven仓库,进入Sonatype JIRA注册,再去Dashboard新建一个问题,类型选new project
,申请时需要域名,可以用github.io
,但是需要新建一个公开仓库取名为你的问题编号用来验证,可以参考我的问题,一般五分钟内就会有回复,如果机器人报错需要及时修改重新申请,二次申请大约十分钟(别问我为什么知道 >_< )
配置pom.xml文件
最后就需要配置pom.xml
文件了,但这也是笔者认为最难的一步,首先需要在你的maven的setting.xml
中添加以下内容以保证中央仓库的访问权:
<server>
<id>ossrh</id>
<username>your-username</username>
<password>your-password</password>
</server>
其次配置pom.xml
文件模版如下,也可以参考机器人发的指南读者自己参考写吧,能不能用就随缘了,反正我可以用:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>io.github.steadon</groupId>
<artifactId>utils</artifactId>
<version>1.2.0</version>
<packaging>jar</packaging>
<name>JWTUtils</name>
<url>https://github.com/steadon/JWTUtils</url>
<description>Fast token generation and parsing based on springboot</description>
<!-- 开源签名证书 -->
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<!-- 开发人员信息 -->
<developers>
<developer>
<name>steadon</name>
<email>1473352497@qq.com</email>
<organization>https://github.com/steadon</organization>
<timezone>+8</timezone>
</developer>
</developers>
<!-- 仓库信息 -->
<scm>
<connection>scm:git:git://github.com/steadon/JWTUtils.git</connection>
<developerConnection>scm:git:ssh://github.com/steadon/JWTUtils.git</developerConnection>
<url>http://github.com/steadon/JWTUtils</url>
</scm>
<!-- 发布项目到 sonatype -->
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<properties>
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<gpg.executable>gpg</gpg.executable>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
如果读者成功上传了自己的依赖记得来给我star!!!