上周看了一下jwt以前公司的开发都是使用session共享的方法。现在主流的两种方式一种是把登录信息保存在服务器,另一种则是把信息保存在客户端。在使用session 存储的时候会遇到很多的问题,随着项目越来越多工作量会变得越来越大。现在公司要开始一个新的项目,索性就开始使用jwt,数据保存在客户端每一次请求都回传给服务器验证一下。

本文分为两部分第一部分简单介绍一下JWT,第二部分简单介绍一下使用spring boot+jwt构建一个项目。

一、什么是JWT?

JWT全程JSON Web tokens 主要由 三部分组成通过“.”分割开,三部分分别是Header、Payload、Signature因此一个完成的JWT经典结构体应该是xxxx.yyyy.zzzzz

1.Header (头)

头部是一个包括了两部分的JSON 一部分是签名的算法(alg)通常使用HS256或者RSA,这里基本上都是使用HS256,还有一个部分是签名类型(typ)即JWT

例如:

{
"alg": "HS256",
"typ": "JWT"
}

然后把这个JSON Base64Url,形成第一部分。

2.Payload (数据)

第二部分也是一个JSON对像,官方提供了几个数据字段 iss (issuer):签发人、exp (expiration time):过期时间、sub (subject):主题、aud (audience):受众、nbf (Not Before):生效时间、iat (Issued At):签发时间、jti (JWT ID):编号

除了官方字段还可以定义私有字段

如例:

{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}

  然后和第一部分一样使用Base64Url算法转化一下,由于这部分直接是暴露出去的顾不应该放比较重要的数据。

3.Signature

Signature 部分是对前两部分的签名,防止数据篡改。

首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)

算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。

关于jwt的介绍就到这里 ,参考了网上的其他人博客和JWT官网想要了解的更加详细可以前去官网仔细阅读一下。

二、构建demo

首先新建一个spring boot 项目 pom文件如下

 <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.7.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

  然后新建一个实体类user 包括了id,name,password和一个EntRespon用于网络之间消息的传输。

public class User {
private String id;
private String name;
private String password; public String getId() {
return id;
} public void setId(String id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
}
}

  

public class EntRespson {
private int code;
private String resultMsg;
private Object data; public EntRespson() {
this.code=0;
} public int getCode() {
return code;
} public void setCode(int code) {
this.code = code;
} public String getResultMsg() {
return resultMsg;
} public void setResultMsg(String resultMsg) {
this.resultMsg = resultMsg;
} public Object getData() {
return data;
} public void setData(Object data) {
this.data = data;
}
}

   然后新建一个controller 先写一个测试方法 test 先测试没有问题 。然后我们需要完成一个JWT加密解密的方法,以下使我们的一个简单的JWT加密解密的方法。

public class JwtUtils {

    public static final String TOKEN_HEADER = "Authorization";
public static final String TOKEN_PREFIX = "Bearer "; private static final String SECRET = "jwtdemo";
private static final String ISS = "echisan"; // 过期时间
private static final long EXPIRATION = 360000l; /**
* 加密 jwt token
* @param id
* @return
*/
public static String encode(String id) {
Algorithm algorithm = Algorithm.HMAC256(SECRET);
String token = JWT.create()
//设置过期时间为一个小时
.withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION))
//设置负载
.withJWTId(id)
.sign(algorithm);
return token;
} /**
* 解密 jwt toke
* @param token
* @return
*/
public static String decode(String token) {
if (token == null || token.length() == 0) {
throw new RuntimeException("token为空:" + token);
}
Algorithm algorithm = Algorithm.HMAC256(SECRET);
JWTVerifier jwtVerifier = JWT.require(algorithm).build();
DecodedJWT decodedJWT = jwtVerifier.verify(token);
return decodedJWT.getId();
} }

     由于我们这demo没有连接数据库所以我把用户信息写在配置文件里面了 application.properties 如下

demo.name=lee
demo.password=123
demo.id=1

  然后我们完成一个读取配置文件的类

@Configuration
@PropertySource("classpath:application.properties")
public class UserConfig {
@Value("${demo.name}")
private String name;
@Value("${demo.password}")
private String password;
@Value("${demo.id}")
private String id; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} public String getId() {
return id;
} public void setId(String id) {
this.id = id;
}
}

  

这个时候完成controller 里面的登录方法,在登录完成后 生成一个token返还给前端这个就是一个获取受保护的凭证。

@RestController
public class CtrlUser {
@Autowired
private UserConfig config; @RequestMapping("test1")
public String test() {
return "ok test" + config.getName();
} @RequestMapping(value = "login", method = RequestMethod.POST)
public EntRespson login(@RequestBody User user) {
EntRespson entRespson = new EntRespson();
try {
String usename = config.getName();
String pwds = config.getPassword();
if (!(user.getName().equals(usename) &&
user.getPassword().equals(pwds)))throw new Exception("账户密码错误");
//登录成功获得token
String token = JwtUtils.encode(config.getId());
JSONObject jsonObject = new JSONObject();
jsonObject.put("token",token);
entRespson.setData(jsonObject);
} catch (Exception e) {
entRespson.setCode(-1);
entRespson.setResultMsg(e.getMessage());
}
return entRespson;
}
}

 现在我们还是完成一个简单的拦截器的功能。

public class Interceptor implements HandlerInterceptor {
@Autowired
private UserConfig config;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("token");// HttpServletRequest 请求头中取出 token
if (!(handler instanceof HandlerMethod)) {
return true;
} // HandlerMethod handlerMethod = (HandlerMethod) handler;
// Method method = handlerMethod.getMethod();
// //检查是否有passtoken注释,有则跳过认证
// if (method.isAnnotationPresent(SkipToken.class)) {
// SkipToken passToken = method.getAnnotation(SkipToken.class);
// if (passToken.required()) {
// return true;
// }
// }
String id = JwtUtils.decode(token);
if (id.equals(config.getId()))
return true;
return false;
} @Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { }
}

  把拦截器添加到配置类中

@Configuration
public class InterceptorConfig implements WebMvcConfigurer { @Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getInterceptor())
.addPathPatterns("/**") //配置拦截所有请求
.excludePathPatterns("/login"); // 不拦截登录请求。
} @Bean
public Interceptor getInterceptor(){
return new Interceptor();
}
}

  好了 到此为止我们的demo已经完成了我们开始测试我们是demo。

启动完成之后我们先试试127.0.0.1:8080/test1

   这里可以看到我们请求被拒绝了 ,然后我们测试一下登录接口。

到这里我们已经获取到了token,前端在获取了token之后前端是逻辑是需要在每一次请求的Headers里面增加一个token,我们在上一个测试接口里面加上token重新请求一下

好的在这里我们已经能看到了我们带有token的请求已经访问成功了。

最后附上源码地址:https://github.com/llcin/spring_tool/tree/master/mydemo

spring boot+jwt 权限验证的更多相关文章

  1. (39.4) Spring Boot Shiro权限管理【从零开始学Spring Boot】

    在读此文章之前您还可能需要先了解: (39.1) Spring Boot Shiro权限管理[从零开始学Spring Boot] http://412887952-qq-com.iteye.com/b ...

  2. (39.2). Spring Boot Shiro权限管理【从零开始学Spring Boot】

    (本节提供源代码,在最下面可以下载) (4). 集成Shiro 进行用户授权 在看此小节前,您可能需要先看: http://412887952-qq-com.iteye.com/blog/229973 ...

  3. (39.1) Spring Boot Shiro权限管理【从零开始学Spring Boot】

    (本节提供源代码,在最下面可以下载)距上一个章节过了二个星期了,最近时间也是比较紧,一直没有时间可以写博客,今天难得有点时间,就说说Spring Boot如何集成Shiro吧.这个章节会比较复杂,牵涉 ...

  4. Spring Boot Shiro 权限管理

    Spring Boot Shiro 权限管理 标签: springshiro 2016-01-14 23:44 94587人阅读 评论(60) 收藏 举报 .embody{ padding:10px ...

  5. Spring Boot JWT 快速入门

    本章节讨论 jwt 在 spring boot 中的应用.意在快速入门 jwt. java jdk1.8 maven 3.2+ spring boot 2.0+ JSON Web Token(JWT) ...

  6. (39.3) Spring Boot Shiro权限管理【从零开始学Spring Boot】

    在学习此小节之前您可能还需要学习: (39.1) Spring Boot Shiro权限管理[从零开始学Spring Boot] http://412887952-qq-com.iteye.com/b ...

  7. Z从壹开始前后端分离【 .NET Core2.2/3.0 +Vue2.0 】框架之五 || Swagger的使用 3.3 JWT权限验证【必看】

    本文梯子 本文3.0版本文章 前言 1.如何给接口实现权限验证? 零.生成 Token 令牌 一.JWT ——自定义中间件 0.Swagger中开启JWT服务 1:API接口授权策略 2.自定义认证之 ...

  8. Spring Boot整合实战Spring Security JWT权限鉴权系统

    目前流行的前后端分离让Java程序员可以更加专注的做好后台业务逻辑的功能实现,提供如返回Json格式的数据接口就可以.像以前做项目的安全认证基于 session 的登录拦截,属于后端全栈式的开发的模式 ...

  9. 十、 Spring Boot Shiro 权限管理

    使用Shiro之前用在spring MVC中,是通过XML文件进行配置. 将Shiro应用到Spring Boot中,本地已经完成了SpringBoot使用Shiro的实例,将配置方法共享一下. 先简 ...

随机推荐

  1. codeforces C. Primes and Multiplication(快速幂 唯一分解定理)

    题目链接:http://codeforces.com/contest/1228/problem/C 题解:给定一个函数f,g,题目有描述其中的表达式含义和两者之间的关系. 然后计算: 首先把给定的x用 ...

  2. .net core各种修改环境变量的方式

    除了修改系统变量,或者程序硬编码中修改,还有以下方法: 发布在IIS中,修改web.config <environmentVariables> <environmentVariabl ...

  3. GitHub网页版基本操作

    创建存储库 登录GitHub进入主页,点击头像左边的加号,创建存储库 填写存储库名称.描述,根据需求设置其他选项.点击“Create repository”按钮 创建分支 打开之前创建好的存储库,点击 ...

  4. 题解【洛谷P5436】【XR-2】缘分

    题目背景 世间万物都置身于缘分编织的大网中.缘分未到,虽历经千劫,却不能相遇.缘分到了,在草原上都能等到一艘船.--<一禅小和尚> 题目描述 一禅希望知道他和师父之间的缘分大小.可是如何才 ...

  5. NUMPY的学习之路(2)——索引,合并,分割,赋值

    一.索引 1.1numpy数组的转置 A=np.arange(3,15).reshape(3,4) print(A) print(A[2][0]) print(A[2,1]) print(A[2,:] ...

  6. 部署DVWA时的一些问题和解决办法(一)

    第一个有可能遇到的问题 0x4 配置PHP 配置PHP,GD支持 系统从2017更新到2018多个php版本共存问题解决,phpinfo 显示7.0 ,而php -v 显示7.2问题 apt-get ...

  7. Visual Studio 2017进行Python开发环境的搭建,使用VS2017进行python代码的编写。

    Visual Studio 2017进行Python开发环境的搭建,使用VS2017进行python代码的编写. 前提:已经安装过VS2017且进行过配置. 第一部分: Python环境的搭建: 建议 ...

  8. 唠唠C++二级指针、二维数组、指针数组、数组指针等的区分

    今天看c++primer第六章,有这部分的内容,脑子有点糊涂了,看了几篇博客,自己敲了下,记录一下备忘. 二级指针: int **p; 二维数组: int p[10][10]; char q[10][ ...

  9. Django+Celery+redis kombu.exceptions.EncodeError:Object of type is not JSON serializable报错

    在本文中例子中遇到问题的各种开发版本如下: Python3.6.8 Django==2.2 celery==4.4.0 kombu==4.6.7 redis==3.3.0 大概的报错如下截图: 是在开 ...

  10. JS高级---原型的简单的语法

    原型的简单的语法 构造函数,通过原型添加方法,以下语法,手动修改构造器的指向 实例化对象,并初始化,调用方法 <!DOCTYPE html> <html lang="en& ...