当前位置: 首页 > article >正文

Spring Boot项目中集成sa-token实现认证授权和OAuth 2.0第三方登录

OAuth 2.0第三方登录

OAuth 2.0 是一种授权协议,允许第三方应用在不暴露用户密码的情况下访问用户的资源。它通常用于第三方登录场景,例如使用GitHub、Google等社交平台进行登录。

sa-token框架中,OAuth 2.0第三方登录可以通过集成sa-token-oauth2模块来实现,并且可以结合sa-token的安全特性来增强安全性。

导入依赖

首先,在你的pom.xml文件中添加必要的依赖,包括sa-token核心模块、MyBatis、数据库驱动等,特别是要导入sa-token-oauth2模块。

<dependencies>
    <!-- sa-token 核心模块 -->
    //如果你使用的是 SpringBoot 3.x,只需要将 sa-token-spring-boot-starter 修改为 sa-token-spring-boot3-starter 即可。
    <dependency>
        <groupId>cn.dev33</groupId>
        <artifactId>sa-token-spring-boot-starter</artifactId>
        <version>1.40.0</version>
    </dependency>

    <!-- Sa-Token OAuth2.0 模块 -->
    <dependency>
        <groupId>cn.dev33</groupId>
        <artifactId>sa-token-oauth2</artifactId>
        <version>1.40.0</version>
    </dependency>

    <!-- MyBatis Spring Boot Starter -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.0</version>
    </dependency>

    <!-- MySQL Driver -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>

    <!-- Lombok  -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <!-- JSON  -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>

    <!-- Sa-Token SSO  -->
    <dependency>
        <groupId>cn.dev33</groupId>
        <artifactId>sa-token-sso-spring-boot-starter</artifactId>
        <version>1.40.0</version>
    </dependency>
</dependencies>

配置 application.yml

application.yml中配置sate-token、数据库连接信息以及OAuth 2.0提供商的信息。

server:
  port: 8080 # 应用端口

sa-token:
  token-name: satoken  # 指定token的名称,默认是satoken
  timeout: 7200        # 超时时间 (单位秒),这里是2小时
  is-read-body: true   # 是否读取请求体,默认是true
  is-concurrent: false # 是否允许多端登录,默认是false
  is-share: true       # 是否共享Session信息,默认是true
  token-style: uuid    # Token生成风格,默认是uuid

  sso:
    login-url: /sso/login # 单点登录入口地址
    logout-url: /sso/logout # 单点注销入口地址
    callback-url: /sso/callback # 单点登录回调地址

  oauth2:
    client:
      github:
        client-id: your-client-id # 替换为你的GitHub Client ID
        client-secret: your-client-secret # 替换为你的GitHub Client Secret
        redirect-uri: "{baseUrl}/oauth2/code/github" # 回调地址模板
        scope: read:user,user:email # 请求的范围
        user-info-uri: https://api.github.com/user # 用户信息获取URL
        authorization-uri: https://github.com/login/oauth/authorize # 授权URL
        token-uri: https://github.com/login/oauth/access_token # Token获取URL

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/your_database?useSSL=false&serverTimezone=UTC
    username: your_username
    password: your_password
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis:
  mapper-locations: classpath:mapper/*.xml # MyBatis Mapper XML 文件位置
  type-aliases-package: com.example.demo.entity # 实体类包路径

 初始化数据

你可以使用以下SQL语句初始化一些测试数据:

CREATE TABLE users (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(255) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL
);

CREATE TABLE permissions (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL
);

CREATE TABLE user_permissions (
    user_id BIGINT NOT NULL,
    permission_id BIGINT NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users(id),
    FOREIGN KEY (permission_id) REFERENCES permissions(id)
);

INSERT INTO users (username, password) VALUES ('admin', 'password');
INSERT INTO permissions (name) VALUES ('admin:manage'), ('user:view');

INSERT INTO user_permissions (user_id, permission_id) 
SELECT u.id, p.id FROM users u, permissions p WHERE u.username = 'admin' AND p.name IN ('admin:manage', 'user:view');

DTO类

创建一个简单的DTO类用于接收登录请求的数据。

UserLoginDTO.java
package com.example.demo.dto;

public class UserLoginDTO {
    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

创建实体类

创建UserPermission实体类,并映射到数据库表。

User.java
package com.example.demo.entity;

import lombok.Data;
import java.util.Set;

@Data
public class User {
    private Long id; // 用户ID
    private String username; // 用户名
    private String password; // 密码
    private Set<String> permissions; // 权限集合(简化版,直接存储权限字符串)
}
Permission.java
package com.example.demo.entity;

import lombok.Data;

@Data
public class Permission {
    private Long id;
    private String name; // 权限名称
}

创建Mapper接口

创建UserMapper接口来访问数据库。

UserMapper.java
package com.example.demo.mapper;

import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface UserMapper {

    /**
     * 根据用户名查找用户及其权限
     * @param username 用户名
     * @return 用户对象
     */
    @Select("SELECT u.id, u.username, u.password FROM users u WHERE u.username = #{username}")
    User findByUsername(@Param("username") String username);

    /**
     * 查找用户的权限列表
     * @param userId 用户ID
     * @return 权限集合
     */
    @Select("SELECT p.name FROM user_permissions up JOIN permissions p ON up.permission_id = p.id WHERE up.user_id = #{userId}")
    List<String> findPermissionsByUserId(@Param("userId") Long userId);
}

创建Service层

创建UserService接口及其实现类。

UserService.java
package com.example.demo.service;

import com.example.demo.entity.User;

public interface UserService {
    User findByUsername(String username); // 根据用户名查找用户
}
UserServiceImpl.java
package com.example.demo.service.impl;

import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public User findByUsername(String username) {
        // 查找用户基本信息
        User user = userMapper.findByUsername(username);

        if (user != null) {
            // 查找用户的权限列表
            List<String> permissionNames = userMapper.findPermissionsByUserId(user.getId());
            Set<String> permissions = new HashSet<>(permissionNames);
            user.setPermissions(permissions);
        }

        return user;
    }
}

创建Controller层

创建LoginController类来处理用户的登录请求。

LoginController.java
package com.example.demo.controller;

import com.example.demo.dto.UserLoginDTO;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.info.SaTokenInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
public class LoginController {

    @Autowired
    private UserService userService; // 自动注入UserService

    /**
     * 处理用户登录请求
     * @param loginDTO 登录信息
     * @return 登录结果
     */
    @PostMapping("/login") // 映射HTTP POST请求到/login路径
    public ResponseEntity<String> login(@RequestBody UserLoginDTO loginDTO) { // 接收JSON格式的登录信息
        String username = loginDTO.getUsername(); // 获取用户名
        String password = loginDTO.getPassword(); // 获取密码

        // 查找用户
        User user = userService.findByUsername(username); // 从数据库查找用户
        if (user != null && password.equals(user.getPassword())) { // 验证密码
            StpUtil.login(user.getId()); // 登录用户,参数为用户ID
            for (String permission : user.getPermissions()) {
                StpUtil.setPermission(permission); // 设置用户权限
            }
            SaTokenInfo tokenInfo = StpUtil.getTokenInfo(); // 获取token信息
            return ResponseEntity.ok("登录成功, Token: " + tokenInfo.getTokenValue()); // 返回登录成功消息
        }
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("用户名或密码错误"); // 返回错误消息
    }
}

权限校验

使用注解@SaCheckPermission对需要权限控制的方法进行保护。

AdminController.java
package com.example.demo.controller;

import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/admin")
public class AdminController {

    /**
     * 管理后台接口
     * @return 管理后台页面内容
     */
    @SaCheckPermission(value = "admin:manage") // 检查当前用户是否有"admin:manage"权限
    @GetMapping("/manage") // 映射GET请求到/admin/manage路径
    public String manage() {
        return "管理后台"; // 如果权限检查通过,则返回管理后台页面内容
    }
}

OAuth 2.0集成

对于OAuth 2.0第三方登录,我们可以使用sa-token-oauth2模块提供的功能来实现。

OAuth2Controller.java
package com.example.demo.controller;

import cn.dev33.satoken.oauth2.logic.SaOAuth2Manager;
import cn.dev33.satoken.oauth2.config.SaOAuth2Config;
import cn.dev33.satoken.oauth2.logic.SaOAuth2Consts;
import cn.dev33.satoken.oauth2.model.AccessTokenModel;
import cn.dev33.satoken.oauth2.model.AuthTokenModel;
import cn.dev33.satoken.oauth2.model.UserInfoModel;
import cn.dev33.satoken.oauth2.model.CodeModel;
import cn.dev33.satoken.oauth2.logic.SaOAuth2Handle;
import cn.dev33.satoken.oauth2.model.SaClientModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@RestController
@RequestMapping("/oauth2")
public class OAuth2Controller {

    @GetMapping("/login/github")
    public void loginGithub(HttpServletResponse response) throws IOException {
        // GitHub登录
        SaOAuth2Config config = SaOAuth2Manager.getConfig(SaOAuth2Consts.GITHUB);
        SaOAuth2Handle.redirectTo(config);
    }

    @GetMapping("/code/github")
    public String callbackGithub(@RequestParam String code, @RequestParam String state) {
        // GitHub回调处理
        SaOAuth2Config config = SaOAuth2Manager.getConfig(SaOAuth2Consts.GITHUB);
        CodeModel codeModel = new CodeModel(code, state);
        AccessTokenModel accessTokenModel = SaOAuth2Handle.getAccessToken(config, codeModel);
        UserInfoModel userInfoModel = SaOAuth2Handle.getUserInfo(config, accessTokenModel);
        
        // 这里可以添加将用户信息保存到数据库的逻辑
        return "登录成功,欢迎:" + userInfoModel.getUsername();
    }
}

总结

以上步骤详细描述了如何在Spring Boot项目中集成sa-token实现认证授权和OAuth 2.0第三方登录。


http://www.kler.cn/a/584694.html

相关文章:

  • 50.HarmonyOS NEXT 登录模块开发教程(四):状态管理与数据绑定
  • 网络安全工具nc(NetCat)
  • Android7上移植I2C-tools
  • 探索 PyTorch 中的 ConvTranspose2d 及其转置卷积家族
  • SolidWorks中文完整版+教程百度云资源分享
  • 【JavaScript 】1. 什么是 Node.js?(JavaScript 服务器环境)
  • 【Flutter】第一次textEditingController.text获取到空字符串
  • 医院本地化DeepSeek R1对接混合数据库技术实战方案研讨
  • 性能优化:服务器性能影响网站加载速度分析
  • 如何从零编写自己的.NET IoT设备驱动
  • 第54天:Web攻防-SQL注入数据类型参数格式JSONXML编码加密符号闭合复盘报告
  • JVM 详解:Java 虚拟机的核心机制
  • k8s中的控制器的使用
  • DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14_06带搜索功能的固定表头表格
  • Linux C++ 编程死锁详解
  • MyBatis一对多查询方式
  • uniapp实现 uview1 u-button的水波纹效果
  • Jump Desktop for Mac v9.0.94 优秀的远程桌面连接工具 支持M、Intel芯片
  • 数据结构——顺序表seqlist
  • PostgreSQL16 的双向逻辑复制