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中的异常分为两种类型:受检异常(Checked Exception)和非受检异常(Unchecked Exception)。 受检异常 受检异常是指在程序编译或运行时需要处理的异常,这种异常一般是由程序外部因素引起的,比如文件不存在、网络连接中断等等。在Java中,受检异常都是直接…

    Java 2023年5月27日
    00
  • 常用json与javabean互转的方法实现

    下面就为您详细讲解“常用json与javabean互转的方法实现”的完整攻略。 什么是Json和JavaBean? 在讲解Json和JavaBean互转方法之前,我们先来了解一下它们各自是什么。 Json Json(JavaScript Object Notation)是一种轻量级的数据交换格式,具有结构清晰、易于读写、可扩展性强等特点,被广泛地应用于Web…

    Java 2023年5月26日
    00
  • Servlet返回的数据js解析2种方法

    下面是关于Servlet返回的数据js解析2种方法的完整攻略: 方法一:直接使用返回的数据 Servlet返回的数据可以是任意格式的数据,比如JSON、XML或普通的字符串格式等等。如果返回的是JSON格式的数据,我们可以在前端利用JS原生的JSON.parse()方法将其转化成JS对象。例如下面的示例: // 假设这是从Servlet返回的JSON格式的数…

    Java 2023年6月15日
    00
  • maven 标签和标签的使用

    Maven是Java项目的一个重要构建工具,它允许我们轻松地管理项目依赖项和插件。 Maven中的repositories标签和pluginRepositories标签可以让我们指定Maven用于下载项目依赖项和插件的远程仓库。 标签 repositories标签让我们指定从哪些远程仓库中下载项目的依赖项。当Maven需要下载依赖项时,它将首先在本地仓库中查…

    Java 2023年5月20日
    00
  • Apache Commons fileUpload文件上传多个示例分享

    Apache Commons FileUpload 文件上传多个示例分享 介绍 Apache Commons FileUpload 是一个用 Java 实现的文件上传组件,它提供了一种方便的方式来解析 HTTP 请求中的多部分内容。此组件可以帮助开发者处理各种类型的文件上传。在本文中,我们将探讨如何使用 Apache Commons FileUpload 来…

    Java 2023年6月15日
    00
  • java中的session对象及其常用方法小结

    下面我将为你详细讲解“java中的session对象及其常用方法小结”的攻略。 Session对象是什么? Session是Servlet技术中的一个概念,用来存储客户端与服务器之间的交互信息。在Web开发中,服务器为每个访问它的客户端创建一个Session对象,用于存储客户端的一些状态信息。Session对象主要用于在多个请求之间存储客户端的数据,以便与客…

    Java 2023年6月15日
    00
  • springboot注册bean的三种方法

    以下是详细讲解“Spring Boot注册Bean的三种方法”的攻略。 简介 在Spring Boot应用程序中,可以使用三种方法注册Bean: @ComponentScan + @Component 注册:使用注解扫描机制,标记bean组件并创建自动扫描Spring Boot应用程序中的bean。可以在类上使用@Component、@Service、@Re…

    Java 2023年5月15日
    00
  • Serv-U 8.0 服务器中文乱码问题的解决

    这里是 Serv-U 8.0 服务器中文乱码问题的解决攻略。 问题描述 在 Serv-U 8.0 服务器中,当有中文字符传输时,会出现乱码问题,影响文件传输的正常使用。 解决方案 方案一:修改 Serv-U 的默认编码格式 Serv-U 8.0 服务器默认采用 ISO-8859-1 编码格式,而中文字符需要使用 UTF-8 编码格式才能正确显示。因此,我们需…

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