在前后端开发时为什么需要用户认证呢?原因是由于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. 使用nodejs + wecharty打造你的个人微信机器人

    开源地址:https://github.com/isnl/wechat-robot 注: 从2017年6月下旬开始,使用基于web版微信接入方案存在大概率的被限制登陆的可能性. 主要表现为:无法登陆W ...

  2. 【总结】Centos中,Kerberos安装

    1.安装软件包 安装必须的工具 bison, make, binutils 下载压缩包至/usr/local目录下,并解压 [root@localhost local]# ls krb5-1.14.t ...

  3. bootstrap-分页-默认分页

    说明 默认分页 示例 <!DOCTYPE html> <html lang="zh-CN">    <head>      <meta c ...

  4. SocksCap64应用程序通过SOCKS代理

    一.下载SocksCap64 https://pan.baidu.com/s/1B671kT9R6Zb6ch1mc4Kb2Q 提取码:hai3 一个是免安装版本,一个是安装版本,选一个即可. 下面以免 ...

  5. ACM思维题训练 Section A

    题目地址: 选题为入门的Codeforce div2/div1的C题和D题. 题解: A:CF思维联系–CodeForces -214C (拓扑排序+思维+贪心) B:CF–思维练习-- CodeFo ...

  6. Codeforces Round #530 (Div. 1) 1098A Sum in the tree

    A. Sum in the tree Mitya has a rooted tree with nn vertices indexed from 11 to nn, where the root ha ...

  7. startUML简单使用教程

    最近在startUML上画图搞得我一个头两个大,找了一些比较实用的小方法分享给大家. 类图是可视化地表现类的属性和方法,以及类与类之间的关系. 1.类 a.类 普通实体类,它有对应的属性和方法: 双击 ...

  8. C语言程序报告五

    C程序设计实验报告 姓 名:赖瑾 实验地点:家 实验时间: 2020年4月21日 实验项目:6.3.1练习1 编写由三角形三边求面积的函数 6.3.1练习2 编写求N阶乘的函数 6.3.1练习3 求两 ...

  9. C. Fountains

    \(整体思路没错,但是我貌似太麻烦了.......\) \(分情况讨论\) \(Ⅰ.coin和diamond各选一个物品,这个简单\) \(Ⅱ.在coin中选两个或者在diamond选两个\) \(开 ...

  10. CGI (通用网关接口)

    CGI cgi即 Common Gateway Interface 译作 通用网关接口 是应用程序与应用程序之间的输入输出协议.比如我们写信,规定了开头一句写称呼,中间写内容,最后署名和日期.看到这种 ...