springcloud oauth2 自定义token实现

1 请求参数类

复制代码
package com.shpl.scp.admin.api.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.ArrayList;
import java.util.List;

@Data
public class UserTokenDTO {

    // 请求信封:装载我们要发送的数据
    @Data
    public static class Request {
        private String username;  // 用户名(必填)
        private List<String> authorities = new ArrayList<>();  // 用户权限列表(可选)
    }

    // 响应信封:装载系统返回给我们的数据
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Response {
        private String accessToken;   // 访问令牌(主要的通行证)
        private String refreshToken;  // 刷新令牌(用来获取新的访问令牌)
    }
}

2 auth服务权限认证请求实现方法

复制代码
/**
     * 获取token  -  自定义token
     * @param request 请求参数
     * @return {@link UserTokenDTO.Response}
     */
    @Inner  // 这个注解表示只有内部系统可以调用
    @SneakyThrows
    @PostMapping("/token/generate-token")
    public R<UserTokenDTO.Response> generateToken(@RequestBody UserTokenDTO.Request request) {

        // 第1步:创建一个"客户端配置",告诉系统这个Token的基本规则
        RegisteredClient registeredClient = RegisteredClient.withId(SecurityConstants.FROM)
                .clientId(SecurityConstants.FROM)
                .authorizationGrantType(AuthorizationGrantType.PASSWORD)
                .tokenSettings(TokenSettings.builder()
                        .accessTokenTimeToLive(Duration.ofHours(24)) // Token有效期:24小时
                        .refreshTokenTimeToLive(Duration.ofDays(7))  // 刷新Token有效期:7天
                        .accessTokenFormat(OAuth2TokenFormat.REFERENCE)
                        .build())
                .build();

        // 第2步:构建用户信息对象
        // 这里我们根据传入的用户名创建一个完整的用户对象
        ScpUser pigUser = new ScpUser(
                110L,                    // 用户ID
                request.getUsername(),   // 用户名
                null,                    // 密码(这里不需要)
                "", "", "", "", "",      // 其他用户信息(暂时为空)
                1L,                      // 部门ID
                "",                      // 其他信息
                true, true,              // 账户状态
                UserTypeEnum.TOB.getStatus(),
                true, false,
                // 将权限字符串转换为系统认识的权限对象
                request.getAuthorities().stream()
                        .map(SimpleGrantedAuthority::new)
                        .collect(Collectors.toList())
        );

        // 第3步:创建认证对象
        Authentication usernamePasswordAuthentication =
                new UsernamePasswordAuthenticationToken(pigUser, StrUtil.EMPTY);

        // 第4步:设置Token生成的上下文环境
        DefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder()
                .registeredClient(registeredClient)
                .principal(usernamePasswordAuthentication)
                .authorizationServerContext(new AuthorizationServerContext() {
                    @Override
                    public String getIssuer() {
                        return "http://ai.com";  // Token发行者
                    }

                    @Override
                    public AuthorizationServerSettings getAuthorizationServerSettings() {
                        return AuthorizationServerSettings.builder().build();
                    }
                });

        // 第5步:开始构建授权信息
        OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization
                .withRegisteredClient(registeredClient)
                .principalName(usernamePasswordAuthentication.getName());

        // 第6步:生成访问Token(主要的通行证)
        OAuth2TokenContext tokenContext = tokenContextBuilder
                .tokenType(OAuth2TokenType.ACCESS_TOKEN)
                .authorizationGrantType(AuthorizationGrantType.PASSWORD)
                .authorizationGrant(new OAuth2ClientAuthenticationToken(
                        registeredClient,
                        ClientAuthenticationMethod.CLIENT_SECRET_BASIC,
                        null))
                .build();

        OAuth2Token generatedAccessToken = this.tokenGenerator.generate(tokenContext);
        OAuth2AccessToken accessToken = new OAuth2AccessToken(
                OAuth2AccessToken.TokenType.BEARER,
                generatedAccessToken.getTokenValue(),
                generatedAccessToken.getIssuedAt(),
                generatedAccessToken.getExpiresAt(),
                tokenContext.getAuthorizedScopes());

        // 第7步:保存访问Token信息
        if (generatedAccessToken instanceof ClaimAccessor) {
            authorizationBuilder.id(accessToken.getTokenValue())
                    .token(accessToken, (metadata) -> metadata.put(
                            OAuth2Authorization.Token.CLAIMS_METADATA_NAME,
                            ((ClaimAccessor) generatedAccessToken).getClaims()))
                    .attribute(Principal.class.getName(), usernamePasswordAuthentication);
        } else {
            authorizationBuilder.id(accessToken.getTokenValue()).accessToken(accessToken);
        }

        // 第8步:生成刷新Token(用来获取新的访问Token)
        OAuth2RefreshToken refreshToken;
        tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.REFRESH_TOKEN).build();
        OAuth2Token generatedRefreshToken = this.tokenGenerator.generate(tokenContext);
        refreshToken = (OAuth2RefreshToken) generatedRefreshToken;
        authorizationBuilder.refreshToken(refreshToken);

        // 第9步:保存完整的授权信息到数据库
        OAuth2Authorization authorization = authorizationBuilder
                .authorizationGrantType(AuthorizationGrantType.PASSWORD)
                .build();
        this.authorizationService.save(authorization);

        // 第10步:返回生成的Token
        return R.ok(new UserTokenDTO.Response(
                accessToken.getTokenValue(),
                refreshToken.getTokenValue()));
    }

3 自定义获取token传递用户名和角色参数

复制代码
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/external/cloudpense")
@Tag(description = "cloudcheckToken", name = "云检系统Token接口")
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
public class FinApiCloudPenseTokenController {

    private final RemoteTokenService remoteTokenService;

    @Inner(false)
    @RequestMapping("/token")
    public R<UserTokenDTO.Response> token() {
        // 创建请求对象
        UserTokenDTO.Request request = new UserTokenDTO.Request();
        request.setUsername("FinCloudPenseAPI");  // 只需要提供用户名
        request.setAuthorities(List.of("ROLE_1", "fin_external_cloudpense")); // 设置用户角色(ROLE_ID 固定写法)权限字符串

        // 调用Token生成服务
        return remoteTokenService.generateToken(request);
    }

    @Inner(false)
    @RequestMapping("/tokenp")
    public R<Page> tokenp() {
        // 创建请求对象
        Map<String, Object> params = Map.of("current", 1, "size", 10);
        // 调用Token生成服务
        return remoteTokenService.getTokenPage(params);
    }

}

4 第三方API对接使用权限注解判断 ,用户拥有权限 @HasPermission("fin_external_cloudpense")才能访问接口方法

复制代码
/**
     * 重新解析数据
     * @return R
     */
    @Operation(summary = "重新解析数据", description = "重新解析数据")
    @PostMapping("/v1/repeatParseReceive")
    @HasPermission("fin_external_cloudpense")
    public R repeatParseReceive(@RequestBody FinApiFinanceInboxLogsDTO finApiFinanceInboxLogsDTO) {

        try {
            LambdaQueryWrapper<FinApiFinanceInboxLogsEntity> wrapper = Wrappers.lambdaQuery();
            wrapper.eq(finApiFinanceInboxLogsDTO.getId()!=null,FinApiFinanceInboxLogsEntity::getId, finApiFinanceInboxLogsDTO.getId());
            List<FinApiFinanceInboxLogsEntity> list = finApiFinanceInboxLogsService.list(wrapper);
            for (FinApiFinanceInboxLogsEntity logsEntity : list){
                // 异步调用处理方法 - 数据拆分逻辑
                finApiCloudPenseDataAsyncService.processRawDataAsync(logsEntity);
            }
            return R.ok("原始数据接收成功");
        } catch (Exception e) {
            log.error("接收原始JSON数据异常: ", e);
            return R.failed("原始数据接收失败: " + e.getMessage());
        }
    }
相关推荐
pixcarp2 小时前
Nginx实战部署与踩坑总结 附带详细配置教程
服务器·前端·后端·nginx·golang
神奇小汤圆2 小时前
JAVA 面经汇总2026最新版,1100+ 大厂面试题附答案详解
后端
程序员老邢2 小时前
【技术底稿 23】Ollama + Docker + Ubuntu 部署踩坑实录:网络通了,参数还在调
java·经验分享·后端·ubuntu·docker·容器·milvus
大龄码农-涵哥2 小时前
Spring Cloud微服务架构详解:从服务注册到配置中心,阿里面试核心知识点
spring cloud·微服务·架构
JackSparrow4142 小时前
彻底理解Java NIO(一)C语言实现 单进程+多进程+多线程 阻塞式I/O 服务器详解
java·linux·c语言·网络·后端·tcp/ip·nio
小江的记录本2 小时前
【微服务与云原生架构】Serverless架构、FaaS/BaaS、核心原理、优缺点
java·后端·微服务·云原生·架构·系统架构·serverless
神奇小汤圆2 小时前
阿里云社招一面:数据库中有 1000 万数据的时候怎么分页查询?
后端
下地种菜小叶2 小时前
特征定义、特征计算、特征服务怎么配合?一次讲透
java·服务器·前端·数据库·spring cloud
威迪斯特2 小时前
Cobra框架:Go语言命令行开发的现代化利器
开发语言·前端·后端·golang·cobra·交互模型·命令行框架