Java实现JWT的Token认证机制

io.jsonwebtoken

jjwt

0.6.0

(2)创建类CreatejwtTest,用于生成token

public class CreateJwtTest {

public static void main(String[] args) {

JwtBuilder builder= Jwts.builder().setId(“888”)

.setSubject(“小白”)

.setIssuedAt(new Date())//用于设置签发时间

.signWith(SignatureAlgorithm.HS256,“wangmh”);//用于设置签名秘钥

System.out.println( builder.compact() );

}

}

(3)测试

eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1MjM0M

TM0NTh9.gq0J‐cOM_qCNqU_s‐d_IrRytaNenesPmqAIhQpYXHZk

#再次运行,每次运行结果都会不一样,因为我们载荷中包含了时间

3.token的解析

public class ParseJwtTest {

public static void main(String[] args) {

String compactJws=“eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1MjM0MTM0NTh9.gq0J‐cOM_qCNqU_s‐d_IrRytaNenesPmqAIhQpYXHZk”;

Claims claims =

Jwts.parser().setSigningKey(“wangmh”).parseClaimsJws(compactJws).getBody();

System.out.println(“id:”+claims.getId());

System.out.println(“subject:”+claims.getSubject());

System.out.println(“IssuedAt:”+claims.getIssuedAt());

}

}

//试着将token或签名秘钥篡改一下,会发现运行时就会报错,所以解析token也就是验证token

4.token过期校验

有很多时候,我们并不希望签发的token是永久生效的,所以我们可以为token添加一个

过期时间。

public class CreateJwtTest2 {

public static void main(String[] args) {

//为了方便测试,我们将过期时间设置为1分钟

long now = System.currentTimeMillis();//当前时间

long exp = now + 1000*60;//过期时间为1分钟

JwtBuilder builder= Jwts.builder().setId(“888”)

.setSubject(“小白”)

.setIssuedAt(new Date())

.signWith(SignatureAlgorithm.HS256,“wangmh”)

.setExpiration(new Date(exp));//用于设置过期时间

System.out.println( builder.compact() );

}

}

public class ParseJwtTest {

public static void main(String[] args) {

String compactJws=“eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1MjM0MTY1NjksImV4cCI6MTUyMzQxNjYyOX0.Tk91b6mvyjpKcldkic8DgXz0zsPFFnRgTgkgcAsa9cc”;

Claims claims =Jwts.parser().setSigningKey(“wangmh”).parseClaimsJws(compactJws).getBody();

System.out.println(“id:”+claims.getId());

System.out.println(“subject:”+claims.getSubject());

SimpleDateFormat sdf=new SimpleDateFormat(“yyyy‐MM‐dd hh:mm:ss”);

System.out.println(“签发时间:”+sdf.format(claims.getIssuedAt()));

System.out.println(“过期时间:”+sdf.format(claims.getExpiration()));

System.out.println(“当前时间:”+sdf.format(new Date()) );

}

}

//测试运行,当未过期时可以正常读取,当过期时会引发io.jsonwebtoken.ExpiredJwtException异常。

5.自定义claims

我们刚才的例子只是存储了id和subject两个信息,如果你想存储更多的信息(例如角色)可以定义自定义claims

public class CreateJwtTest3 {

public static void main(String[] args) {

//为了方便测试,我们将过期时间设置为1分钟

long now = System.currentTimeMillis();//当前时间

long exp = now + 1000*60;//过期时间为1分钟

JwtBuilder builder= Jwts.builder().setId(“888”)

.setSubject(“小白”)

.setIssuedAt(new Date())

.signWith(SignatureAlgorithm.HS256,“wangmh”)

.setExpiration(new Date(exp))

.claim(“roles”,“admin”)

.claim(“logo”,“logo.png”);

System.out.println( builder.compact() );

String compactJwt = “eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1NTQ5NDcxNTksImV4cCI6MTU1NDk0NzIxOSwicm9sZXMiOiJhZG1pbiIsImxvZ28iOiJsb2dvLnBuZyJ9.HD_myvdNjOGGnu4p8Z8QX9dnXHJEZa0nsLKxOFRiYJY”;

Claims claims=Jwts.parser().setSigningKey(“wangmh”).parseClaimsJws(compactJwt).getBody();

System.out.println(“id:”+claims.getId());

System.out.println(“subject:”+claims.getSubject());

System.out.println(“roles:”+claims.get(“roles”));

System.out.println(“logo:”+claims.get(“logo”));

SimpleDateFormat sdf=new SimpleDateFormat(“yyyy‐MM‐dd hh:mm:ss”);

System.out.println(“签发时间:”+sdf.format(claims.getIssuedAt()));

System.out.println(“过期时间:”+sdf.format(claims.getExpiration()));

System.out.println(“当前时间:”+sdf.format(new Date()) );

}

}

6.案例实现

//JwtUtil.java

@ConfigurationProperties(“jwt.config”)

public class JwtUtil {

private String key ;

private long ttl ;//一个小时

public String getKey() {

return key;

}

public void setKey(String key) {

this.key = key;

}

public long getTtl() {

return ttl;

}

public void setTtl(long ttl) {

this.ttl = ttl;

}

/**

  • 生成JWT

  • @param id

  • @param subject

  • @return

*/

public String createJWT(String id, String subject, String roles) {

long nowMillis = System.currentTimeMillis();

Date now = new Date(nowMillis);

JwtBuilder builder = Jwts.builder().setId(id)

.setSubject(subject)

.setIssuedAt(now)

.signWith(SignatureAlgorithm.HS256, key).claim(“roles”, roles);

if (ttl > 0) {

builder.setExpiration( new Date( nowMillis + ttl));

}

return builder.compact();

}

/**

  • 解析JWT

  • @param jwtStr

  • @return

*/

public Claims parseJWT(String jwtStr){

return Jwts.parser()

.setSigningKey(key)

.parseClaimsJws(jwtStr)

.getBody();

}

}

#配置文件

jwt:

config:

key: wangmh

ttl: 3600000

登录鉴权

//Controller.java

@Autowired

private JwtUtil jwtUtil;

@RequestMapping(value=“/login”,method=RequestMethod.POST)

public Result login(@RequestBody Map<String,String> loginMap){

Admin admin =adminService.findByLoginnameAndPassword(loginMap.get(“loginname”),loginMap.get(“password”));

if(admin!=null){

//生成token

String token = jwtUtil.createJWT(admin.getId(),admin.getLoginname(), “admin”);

Map map=new HashMap();

map.put(“token”,token);

map.put(“name”,admin.getLoginname());//登陆名

return new Result(true,StatusCode.OK,“登陆成功”,map);

}else{

return new Result(false,StatusCode.LOGINERROR,“用户名或密码错误”);

}

}

删除用户功能鉴权

@Autowired

private HttpServletRequest request;

/**

  • 删除

  • @param id

*/

@RequestMapping(value=“/{id}”,method= RequestMethod.DELETE)

public Result delete(@PathVariable String id ){

String authHeader = request.getHeader(“Authorization”);//获取头信息

if(authHeader==null){

return new Result(false,StatusCode.ACCESSERROR,“权限不足”);

}

if(!authHeader.startsWith("Bearer ")){

return new Result(false,StatusCode.ACCESSERROR,“权限不足”);

}

String token=authHeader.substring(7);//提取token

Claims claims = jwtUtil.parseJWT(token);

if(claims==null){

return new Result(false,StatusCode.ACCESSERROR,“权限不足”);

}

if(!“admin”.equals(claims.get(“roles”))){

return new Result(false,StatusCode.ACCESSERROR,“权限不足”);

}

userService.deleteById(id);

return new Result(true,StatusCode.OK,“删除成功”);

}

使用拦截器方式实现token鉴权

如果我们每个方法都去写一段代码,冗余度太高,不利于维护。因此我们可以使用拦截器的方式去实现token鉴权

1.添加拦截器

Spring为我们提供了org.springframework.web.servlet.handler.HandlerInterceptorAdapter这个适配器,继承此类,可以非常方便的实现自己的拦截器。他有三个方法:分别实现预处理、后处理(调用了Service并返回ModelAndView,但未进行页面渲染)、返回处理(已经渲染了页面)

在preHandle中,可以进行编码、安全控制等处理;

在postHandle中,有机会修改ModelAndView;

在afterCompletion中,可以根据ex是否为null判断是否发生了异常,进行日志记录。

1.1创建拦截器类

//JwtFilter.java

@Component

public class JwtFilter extends HandlerInterceptorAdapter {

@Autowired

private JwtUtil jwtUtil;

@Override

public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler)throws Exception {

System.out.println(“经过了拦截器”);

final String authHeader = request.getHeader(“Authorization”);

if (authHeader != null && authHeader.startsWith("Bearer ")) {

final String token = authHeader.substring(7); // The partafter "Bearer "

Claims claims = jwtUtil.parseJWT(token);

if (claims != null) {

if(“admin”.equals(claims.get(“roles”))){//如果是管理员

request.setAttribute(“admin_claims”, claims);

}

if(“user”.equals(claims.get(“roles”))){//如果是用户

request.setAttribute(“user_claims”, claims);

}

}

}

return true;

}

}

1.2配置拦截器类

@Configuration

public class ApplicationConfig extends WebMvcConfigurationSupport {

@Autowired

private JwtFilter jwtFilter;

@Override

public void addInterceptors(InterceptorRegistry registry) {

registry.addInterceptor(jwtFilter).

addPathPatterns(“/**”).

excludePathPatterns(“/**/login”);

}

}

1.3删除功能实现

/**

  • 删除

  • @param id

*/

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

/**

  • 删除

  • @param id

*/

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-iqDVi4F1-1715420228346)]

[外链图片转存中…(img-e3bIDCG6-1715420228347)]

[外链图片转存中…(img-rX6QWd4l-1715420228347)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 7
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值