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日

相关文章

  • JSP学习经验小结分享

    JSP学习经验小结分享 本文将分享我学习JSP(JavaServer Pages)的经验,并提供一些示例说明。JSP是一种基于Java的Web开发技术,可以帮助我们创建可重用、动态的Web页面。 学习前的准备工作 在学习JSP之前,需要了解以下基本知识: HTML和CSS:JSP页面是基于HTML和CSS构建的,因此需要了解这些技术; Java基础:JSP技…

    Java 2023年6月15日
    00
  • SpringSecurity OAtu2+JWT实现微服务版本的单点登录的示例

    实现微服务版本的单点登录需要结合SpringSecurity、OAuth2和JWT三个技术点。 首先,关于OAuth2的基础概念和流程可以参考我的博客文章:OAuth2授权模式详解。 接下来就是示例说明: 示例1:SpringBoot微服务注册 在OAuth2客户端程序中添加以下依赖: <dependency> <groupId>or…

    Java 2023年6月3日
    00
  • Java向List集合中批量添加元素的实现方法

    当我们需要向Java中的List类型的集合中批量添加元素时,通常可以使用以下两种方法: 1.使用addAll()方法 List集合的addAll()方法可以接收一个Collection类型的参数,用于将该Collection集合中的元素全部添加到List集合当中。代码示例如下: List<String> list1 = new ArrayList…

    Java 2023年5月26日
    00
  • 深入分析Tomcat无响应问题及解决方法

    深入分析Tomcat无响应问题及解决方法 问题概述 Tomcat是常用的Java Web服务器,但在使用过程中可能会出现无响应问题,导致用户无法访问网站。这种情况可能是由于多种原因造成的,如下所示: Tomcat内存不足 系统负载过高 代码死锁 磁盘I/O瓶颈 网络问题等 在面对无响应问题,我们首先要做的是分析问题,确定问题的原因。 分析问题 要分析无响应问…

    Java 2023年5月20日
    00
  • Java实现超大Excel文件解析(XSSF,SXSSF,easyExcel)

    Java实现超大Excel文件解析攻略 本文介绍使用Java解析超大的Excel文件的方法。Excel文件往往包含大量的数据,有些时候,数据量可能非常之大,如果使用常规的Excel解析方式,很容易出现内存溢出的问题。本文将介绍XSSF、SXSSF和easyExcel三种解析方式,并且对它们进行详细分析和对比。 XSSF XSSF是POI中的一种Excel解析…

    Java 2023年5月19日
    00
  • SpringBoot项目启动时增加自定义Banner的简单方法

    Spring Boot项目启动时增加自定义Banner的简单方法 在Spring Boot项目启动时,我们可以增加自定义Banner,用于展示项目的Logo、名称、版本等信息。在本文中,我们将详细讲解如何增加自定义Banner,包括如何使用文本Banner和如何使用图片Banner。 使用文本Banner 使用文本Banner是最简单的方法,我们只需要在项目…

    Java 2023年5月15日
    00
  • Java中的ConcurrentModificationException是什么?

    Java中的ConcurrentModificationException是一种运行时异常,它表示在使用迭代器(Iterator)遍历集合(例如List、Set、Map等)时,针对集合的某些操作导致了集合的结构发生了修改,从而导致迭代器状态不一致的异常。 具体来说,如果在使用迭代器遍历集合时,另外一个线程改变了集合的结构(比如添加、删除元素等),那么正在遍历…

    Java 2023年4月27日
    00
  • 分享几款linux下常见的vps控制面板

    Linux下有许多VPS(Virtual Private Server,虚拟专用服务器)控制面板可供选择。这些控制面板可以帮助用户通过图形用户界面(GUI)而非命令行来对服务器进行管理。下面将介绍几种在Linux系统下常见的VPS控制面板的安装步骤和使用方法。 1. cPanel cPanel是一个流行的基于Web的Linux控制面板,适用于VPS和独立服务…

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