spring boot如何基于JWT实现单点登录详解

这里是关于如何基于JWT实现Spring Boot单点登录的攻略:

什么是JWT

JWT(JSON Web Token),是一种用于身份验证的标准。它由三部分组成:Header(头部)、Payload(负载)和Signature(签名)。

Header部分一般用于描述Token的类型和 signature使用的算法,例如:

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

Payload部分是JWT的主要内容,例如用户的身份信息、访问权限等,例如:

{
  "userId": "123",
  "name": "Tom",
  "roles": ["admin", "user"]
}

Signature部分是将header和payload加密生成的签名,用于验证JWT的有效性。

JWT使用起来非常方便,可以通过验证签名的方式来确认身份是否合法,不需要再通过服务端的session来存储登录信息。

基于JWT实现Spring Boot单点登录步骤

下面我们就来介绍如何基于JWT实现Spring Boot单点登录。

第一步:添加依赖

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

这里我们使用jjwt作为JWT的依赖库。

第二步:编写TokenUtils类

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class TokenUtils {

    private static final String SECRET = "your_secret_key"; // 生成JWT时使用的密钥
    private static final int EXPIRATION_TIME = 864000000; // JWT过期时间,单位毫秒,这里设置为10天

    public static String createToken(String id, String subject, Map<String, Object> claims) {
        SecretKey key = Keys.hmacShaKeyFor(SECRET.getBytes());
        return Jwts.builder()
                .setId(id)
                .setSubject(subject)
                .addClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .signWith(key, SignatureAlgorithm.HS256)
                .compact();
    }

    public static Claims parseToken(String token) {
        SecretKey key = Keys.hmacShaKeyFor(SECRET.getBytes());
        return Jwts.parserBuilder()
                .setSigningKey(key)
                .build()
                .parseClaimsJws(token)
                .getBody();
    }

}

这里我们定义了两个方法:createToken用于生成JWT Token,parseToken用于解析JWT Token获取其中的信息。其中需要设置:

  • SECRET:生成Token时使用的密钥
  • EXPIRATION_TIME:Token的有效期

第三步:编写登录接口

@RestController
@RequestMapping("/auth")
public class LoginController {

    @PostMapping("/login")
    public Map<String, Object> login(@RequestBody User user) {
        // 校验用户名和密码,如果校验通过,生成JWT Token
        if (checkUser(user)) {
            Map<String, Object> claims = new HashMap<>();
            claims.put("roles", user.getRoles());
            String token = TokenUtils.createToken(user.getId(), user.getUsername(), claims);
            Map<String, Object> result = new HashMap<>();
            result.put("token", token);
            return result;
        } else {
            throw new RuntimeException("登录失败");
        }
    }

    private boolean checkUser(User user) {
        // 校验用户信息,返回true或false
    }

}

在这个接口中,我们首先根据用户提交的用户名和密码进行校验。如果校验通过,我们就可以利用TokenUtils类生成Token并返回给前端。

第四步:编写安全拦截器

@Component
public class AuthInterceptor implements HandlerInterceptor {

    private static final String HEADER_NAME = "Authorization"; // 前端请求头中存储Token的字段名

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader(HEADER_NAME);
        if (StringUtils.isEmpty(token)) {
            throw new RuntimeException("未授权");
        }
        try {
            Claims claims = TokenUtils.parseToken(token);
            request.setAttribute("claims", claims);
            return true;
        } catch (Exception e) {
            throw new RuntimeException("Token无效");
        }
    }

}

在这个安全拦截器中,我们首先从前端提交的请求头中读取Token,并使用TokenUtils类解析其中的内容。如果Token无效,则抛出异常,否则就将解析后的信息存储在request中,以便后续的处理。

示例一:访问需要Token验证的接口

现在我们就可以编写需要Token验证的接口了。例如:

@RestController
@RequestMapping("/api")
public class ApiController {

    @GetMapping("/user/{id}")
    public User getUser(@PathVariable String id, HttpServletRequest request) {
        Claims claims = (Claims) request.getAttribute("claims");
        User user = userService.getUserById(id);
        if (!user.getUsername().equals(claims.getSubject())) {
            throw new RuntimeException("无权限访问");
        }
        return user;
    }

}

在这个接口中,我们通过@PathVariable注解获取用户id,并使用request.getAttribute("claims")获取从Token中解析出的信息。如果当前用户与Token中存储的用户相同,就返回该用户的信息,否则就抛出“无权限访问”的异常。

示例二:单点登录

接下来我们可以在多个应用之间实现单点登录。例如,我们现在有两个应用:

  • app1:http://localhost:8081
  • app2:http://localhost:8082

我们可以在app1中编写如下代码:

@RestController
@RequestMapping("/sso")
public class SsoController {

    @GetMapping("/login")
    public String login(String username, String password) {
        // 校验用户名和密码
        if (checkUser(username, password)) {
            Map<String, Object> claims = new HashMap<>();
            claims.put("roles", "user");
            String token = TokenUtils.createToken(UUID.randomUUID().toString(), username, claims);
            // 登录成功,重定向到app2,并传递Token
            return "redirect:http://localhost:8082/api/cas?ticket=" + token;
        } else {
            return "登录失败";
        }
    }

    private boolean checkUser(String username, String password) {
        // 校验用户信息,返回true或false
    }

}

在这个控制器中,我们首先校验用户名和密码。如果校验通过,我们就生成Token,并将其作为参数传递给app2的接口。app2的接口可以像这样来实现:

@RestController
@RequestMapping("/api")
public class ApiController {

    @GetMapping("/cas")
    public String cas(String ticket) {
        // 使用Token验证用户身份
        Claims claims = TokenUtils.parseToken(ticket);
        if (!"user".equals(claims.get("roles"))) {
            throw new RuntimeException("无权限访问");
        }
        return "登录成功";
    }

}

现在,我们在浏览器中访问http://localhost:8081/sso/login,输入正确的用户名和密码后,就会自动跳转到http://localhost:8082/api/cas页面,并返回“登录成功”的信息。这就实现了单点登录。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:spring boot如何基于JWT实现单点登录详解 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • Java实时获取基金收益项目源码分享

    Java实时获取基金收益项目源码分享 本文介绍使用Java编写程序实时获取基金收益的方法。用户可以输入基金代码,程序会自动访问天天基金网站获取最新的基金收益数据,并实时展示在命令行窗口中。如果用户需要保存数据,程序还提供了将数据保存为CSV文件的功能。 准备工作 在开始编写Java程序之前,需要安装Java开发环境(JDK)以及Maven构建工具。 下载依赖…

    Java 2023年6月1日
    00
  • PHP遍历XML文档所有节点的方法

    背景说明 XML是一种用于数据交换的标记语言。在PHP开发中,我们经常需要遍历XML文档来解析其中的数据。遍历XML节点是XML解析的基础知识之一,本文将详细介绍PHP中遍历XML文档所有节点的方法。 遍历XML文档所有节点的方法 使用PHP内置的SimpleXML库可以方便地遍历XML文档中的节点。以下是遍历XML文档所有节点的步骤: 打开XML文档并读入…

    Java 2023年5月19日
    00
  • Java 方法递归的思路详解

    针对“Java 方法递归的思路详解”,我将针对以下几个方面进行详细讲解: 什么是方法递归? 方法递归的基本思路 方法递归的优缺点 方法递归的应用场景 工程中递归的运用示例 什么是方法递归? 方法递归是指在一个方法内部调用自身的行为,也就是说,一个方法通过调用自己来完成某种功能或者解决某个问题。 方法递归的基本思路 方法递归的基本思路可以概括为以下几个步骤: …

    Java 2023年5月19日
    00
  • HttpClient基础解析

    HttpClient基础解析 什么是HttpClient? HttpClient是Apache软件基金会所提供的一个用于处理HTTP请求的第三方库。其提供了方便的API,使得我们可以通过代码实现HTTP请求的发送与响应的接收。 HttpClient的优点 简单易用:HttpClient提供了方便的API,使得我们可以通过简单的代码实现HTTP请求的发送与响应…

    Java 2023年5月20日
    00
  • Spring纯Java配置集成kafka代码实例

    下面我将详细讲解如何使用Spring纯Java配置集成kafka,包括以下步骤: 添加依赖 配置Kafka 发送消息 接收消息 1. 添加依赖 首先,我们需要在项目的pom.xml中添加kafka相关的依赖,如下所示: <dependency> <groupId>org.springframework.kafka</groupI…

    Java 2023年5月19日
    00
  • Java面试题目集锦

    Java面试题目集锦攻略 1. 概述 本文主要讲解如何通过Java面试题目集锦来提高自己的Java知识和应对面试的能力。Java面试题目集锦是一本经典的Java面试题目集合,在学习Java或准备Java面试时都是非常重要的参考资料。本文将结合自己的学习经验和搜索资料的经验,给大家分享一些从中学习的技巧和方法。 2. 学习方法 2.1. 完整阅读 首先,我们需…

    Java 2023年5月23日
    00
  • JavaWeb动态导出Excel可弹出下载

    引言: 在JavaWeb开发过程中,有时候需要将数据库中的数据导出为Excel文件,然后让用户可以进行下载。而且,下载的过程中需要提供一些提示信息,如下载进度、下载成功等信息。本文将详细介绍如何使用JavaWeb动态导出Excel并实现弹出下载的效果。 步骤: 1.创建Excel文件 我们可以使用Apache POI来创建Excel文件,这里就不过多介绍了,…

    Java 2023年6月15日
    00
  • Java基于IDEA实现http编程的示例代码

    Java基于IDEA实现HTTP编程的示例代码攻略主要分为以下几个步骤: 步骤一:导入依赖 首先需要在项目中导入 httpclient 依赖包。在 pom.xml 文件中添加以下依赖: <dependency> <groupId>org.apache.httpcomponents</groupId> <artifac…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部