在前后端开发时为什么需要用户认证呢?原因是由于HTTP协定是不存储状态的,这意味着当我们透过账号密码验证一个使用者时,当下一个request请求时他就把刚刚的资料忘记了。于是我们的程序就不知道谁是谁了。 所以为了保证系统的安全,就需要验证用户是否处于登陆状态。

一、JWT的组成

JWT由Header、Payload、Signature三部分组成,分别用.分隔。

下面就是一个jwt真实的样子,说白了就是一个字符串,但是里面却存储了很重要的信息。

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJyYXljaGVuIiwiaWQiOjIsIm5hbWUiOiJyYXkiLCJwYXNzd29yZCI6IjMyMSIsImlhdCI6MTU5MDI5OTU0OCwiZXhwIjoxNTkwMzg1OTQ4fQ.ORJNldDIfffg7D3_xu0_dBWb16y4fPLtw_r6qgScFpQ

Header:

第一部分是请求头由两部分组成,algtyp,第一个指定的是算法,第二指定的是类型。

Payload

第二部分是主体信息组成,用来存储JWT基本信息,或者是我们的信息。

Signature

第三部分主要是给第一部分跟第二部进行签名使用的,用来验证是否是我们服务器发起的Token,secret是我们的密钥。

二、在springboot项目中使用jwt做验证

具体流程:

  • 把用户的用户名和密码发到后端
  • 后端进行校验,校验成功会生成token, 把token发送给客户端
  • 客户端自己保存token, 再次请求就要在Http协议的请求头中带着token去访问服务端,和在服务端保存的token信息进行比对校验。

1.先引入jar包

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>

2.使用工具类生成token和验证token(生成token方法中存入了用户的信息)

public class JwtUtils {

    //发行者
public static final String SUBJECT="raychen";
//过期时间 一天
public static final long EXPIRE=1000*60*60*24;
//密钥
public static final String APPSECRET="raychen11"; /**
* 生成jwt
* @param user
* @return
*/
public static String geneJsonWebToken(User user){
if(user==null || user.getId()==null || user.getName()==null || user.getPassword()==null){
return null;
}
String token=Jwts.builder().setSubject(SUBJECT)
.claim("id",user.getId())
.claim("name",user.getName())
.claim("password",user.getPassword())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis()+EXPIRE))
.signWith(SignatureAlgorithm.HS256,APPSECRET).compact(); return token;
} /**
* 校验token
* @param token
* @return
*/
public static Claims checkJWT(String token){
//仿造的token或者已过期就会报错
try {
final Claims claims=Jwts.parser().setSigningKey(APPSECRET).parseClaimsJws(token).getBody();
return claims;
}catch (Exception e){
System.out.println("catch...");
}
return null;
}
}

3.自定义注解(进行token验证)

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

4.编写config,将后台所有请求先去拦截器(拦截器返回了true,用户才可以请求到接口)

@Configuration
public class InterceptorConfig implements WebMvcConfigurer { @Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**"); // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
} @Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
}

5.定义拦截器(对需要token验证的请求,进行验证,验证成功返回true,失败返回false无法请求到接口)

public class AuthenticationInterceptor implements HandlerInterceptor {

    public static final Gson gson=new Gson();
/**
* 进入controller之前进行拦截
* @param request
* @param response
* @param object
* @return
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
// 如果不是映射到方法直接通过
if (!(object instanceof HandlerMethod)) {
return true;
} HandlerMethod handlerMethod = (HandlerMethod) object;
Method method = handlerMethod.getMethod();
//检查是否有LoginToken注释,有则跳过认证
if (method.isAnnotationPresent(LoginToken.class)) {
LoginToken loginToken = method.getAnnotation(LoginToken.class);
if (loginToken.required()) {
return true;
}
} //前面是不需要token验证的 从 http 请求头中取出 token
String token = request.getHeader("token");
//检查有没有需要用户权限的注解
if (method.isAnnotationPresent(CheckToken.class)) {
CheckToken checkToken = method.getAnnotation(CheckToken.class);
if (checkToken.required()) {
if(token!=null){
Claims claims= JwtUtils.checkJWT(token);
if(null==claims){
sendJsonMessage(response, JsonData.buildError("token有误"));
return false;
}
Integer userId= (Integer) claims.get("id");
String name = (String) claims.get("name"); request.setAttribute("userId",userId);
request.setAttribute("name",name);
return true;
}
//token为null的话 返回一段json给前端
sendJsonMessage(response, JsonData.buildError("请登录"));
return false;
}
}
//没有使用注解的方法 直接返回true
return true;
} /**
* 响应数据给前端
* @param response
* @param obj
* @throws IOException
*/
public static void sendJsonMessage (HttpServletResponse response, Object obj) throws IOException {
response.setContentType("application/json; charset=utf-8");
PrintWriter writer = response.getWriter();
writer.print(gson.toJson(obj));
writer.close();
response.flushBuffer();
}
}

用户登录成功后,使用工具类生成token。token在服务端不做存储,直接将token返回给客户端,客户端下次请求服务端时,使用工具类来验证header里的token是否合法。

springboot使用Jwt处理跨域认证问题的更多相关文章

  1. JWT token 跨域认证

    JSON Web Token(缩写 JWT),是目前最流行的跨域认证解决方案. session登录认证方案:用户从客户端传递用户名.密码等信息,服务端认证后将信息存储在session中,将sessio ...

  2. go使用JWT进行跨域认证最全教学

    JWT前言 JWT是JSON Web Token的缩写.JWT本身没有定义任何技术实现,它只是定义了一种基于Token的会话管理的规则,涵盖Token需要包含的标准内容和Token的生成过程. JWT ...

  3. JSON Web Token(缩写 JWT) 目前最流行的跨域认证解决方案

    一.跨域认证的问题 互联网服务离不开用户认证.一般流程是下面这样. 1.用户向服务器发送用户名和密码. 2.服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色.登录时间等等. ...

  4. Cookie、Session、Token与JWT(跨域认证)

    之前看到群里有人问JWT相关的内容,只记得是token的一种,去补习了一下,和很久之前发的认证方式总结的笔记放在一起发出来吧. Cookie.Session.Token与JWT(跨域认证) 什么是Co ...

  5. 干掉Session?这个跨域认证解决方案真的优雅!

    用户登录认证是 Web 应用中非常常见的一个业务,一般的流程是这样的: 客户端向服务器端发送用户名和密码 服务器端验证通过后,在当前会话(session)中保存相关数据,比如说登录时间.登录 IP 等 ...

  6. SpringBoot学习(3)-SpringBoot添加支持CORS跨域访问

    SpringBoot学习(3)-SpringBoot添加支持CORS跨域访问 https://blog.csdn.net/yft_android/article/details/80307672

  7. 2019-03-26 SpringBoot项目部署遇到跨域问题,记录一下解决历程

    近期SpringBoot项目部署遇到跨域问题,记录一下解决历程. 要严格限制,允许哪些域名访问,在application.properties文件里添加配置,配置名可以自己起: cors.allowe ...

  8. SpringBoot添加支持CORS跨域访问

    原文:https://www.jianshu.com/p/c6ea21b64f6e CORS(Cross-Origin Resource Sharing)"跨域资源共享",是一个W ...

  9. Springboot vue.js html 跨域 前后分离 Activiti6 工作流 集成代码生成器 shiro 权限

    官网:www.fhadmin.org 特别注意: Springboot 工作流  前后分离 + 跨域 版本 (权限控制到菜单和按钮) 后台框架:springboot2.1.2+ activiti6.0 ...

随机推荐

  1. uniq 只能相邻行去重

    uniq只可以将相邻行重复数据进行去重处理: [root@localhost /data/mysql/mysql3306]#last | cut -d ' ' -f 1 | tail -15 > ...

  2. 华为设备RIP实施和理论详解

    1.路由协议基础 共同的目的:更新.维护和控制3层的路由 工作机制: RIP,封装在UDP这个协议上,端口号520(优先级100) OSPF,封装在IP层,协议号89(优先级,内部10,外部是150- ...

  3. WFP之位图效果

    首先看一个图片:   在"第一步"这个按钮周围,有一转红色,这个效果就是用WPF的位图效果实现的. 位图效果(BitmapEffect 对象)是简单的像素处理操作.位图效果将 Bi ...

  4. Jaba_Web--JDBC 修改记录操作模板

    import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import ...

  5. 通过例题进一步学习DP

    1.以上篇文章数塔为例 https://blog.csdn.net/weixin_43627118/article/details/88701586 上一章用的是递归的做法,这次我们采用递推的做法. ...

  6. Windows+Ubuntu双系统 ,Ubuntu安装

    这篇只是简单记录自己在Win10下另安装Ubuntu系统. 不是教程,因为不会. 推荐一个教程:https://blog.csdn.net/weixin_37029453/article/detail ...

  7. 4)drf序列化组件 Serializer(偏底层)、ModelSerializer(重点)、ListModelSerializer(辅助群改)

    知识点:Serializer(偏底层).ModelSerializer(重点).ListModelSerializer(辅助群改) 一.Serializer 偏底层 一般不用 理解原理 1.序列化准备 ...

  8. jmeter的正则表达式编辑器

    位置:在后置处理器里面,表示在请求结束或者返回响应结果时发挥作用. 作用:允许用户从服务器的响应中通过使用perl的正则表达式提取值.该元素会作用在指定范围取样器,用正则表达式提取所需值,生成模板字符 ...

  9. socket编程之并发回射服务器2

    承接上文:socket编程之并发回射服务器 为了让服务器进程的终止一经发生,客户端就能检测到,客户端需要能够同时处理两个描述符:套接字和用户输入. 可以使用select达到这一目的: void str ...

  10. 美团分布式ID生成框架Leaf源码分析及优化改进

    本文主要是对美团的分布式ID框架Leaf的原理进行介绍,针对Leaf原项目中的一些issue,对Leaf项目进行功能增强,问题修复及优化改进,改进后的项目地址在这里: Leaf项目改进计划 https ...