java从azure中读取用户信息

以下是用 Java 从 Azure AD 获取用户信息的完整实现方案,使用 Spring Boot 框架和 Microsoft 身份验证库 (MSAL):
 
1. 添加 Maven 依赖

<dependencies>
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- Azure AD MSAL -->
    <dependency>
        <groupId>com.microsoft.azure</groupId>
        <artifactId>msal4j</artifactId>
        <version>1.13.3</version>
    </dependency>
    
    <!-- JWT 处理 -->
    <dependency>
        <groupId>com.nimbusds</groupId>
        <artifactId>nimbus-jose-jwt</artifactId>
        <version>9.25</version>
    </dependency>
    
    <!-- HTTP 客户端 -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.13</version>
    </dependency>
</dependencies>
 

2. 配置 Azure AD 参数
在  application.properties  中:

# Azure AD 配置
azure.client-id=your_client_id
azure.client-secret=your_client_secret
azure.tenant-id=your_tenant_id
azure.redirect-uri=https://your-app.com/auth/redirect
azure.scope=openid profile User.Read
 

3. 控制器实现

import com.microsoft.aad.msal4j.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.net.MalformedURLException;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;

@RestController
public class AuthController {
    
    @Value("${azure.client-id}")
    private String clientId;
    
    @Value("${azure.client-secret}")
    private String clientSecret;
    
    @Value("${azure.tenant-id}")
    private String tenantId;
    
    @Value("${azure.redirect-uri}")
    private String redirectUri;
    
    @Value("${azure.scope}")
    private String scope;
    
    // 第一步:生成登录URL
    @GetMapping("/login")
    public Map<String, String> login() throws MalformedURLException {
        String authUrl = getAuthUrl();
        return Collections.singletonMap("loginUrl", authUrl);
    }
    
    // 第二步:处理回调
    @GetMapping("/auth/redirect")
    public Map<String, Object> handleRedirect(
            @RequestParam("code") String authCode,
            @RequestParam("state") String state
    ) throws Exception {
        
        // 使用授权码获取令牌
        IAuthenticationResult result = acquireToken(authCode);
        
        // 获取用户信息
        Map<String, Object> userInfo = getUserInfo(result.accessToken());
        
        // 返回用户信息
        Map<String, Object> response = new HashMap<>();
        response.put("id_token_claims", result.idToken());
        response.put("user_info", userInfo);
        
        return response;
    }
    
    // 生成认证URL
    private String getAuthUrl() throws MalformedURLException {
        ConfidentialClientApplication app = ConfidentialClientApplication.builder(
                clientId, ClientCredentialFactory.createFromSecret(clientSecret))
                .authority("https://login.microsoftonline.com/" + tenantId)
                .build();
        
        AuthorizationCodeParameters parameters = AuthorizationCodeParameters.builder(
                authCode, 
                new URI(redirectUri)
            ).scopes(Collections.singleton(scope))
             .build();
        
        String authorizationUrl = app.getAuthorizationRequestUrl(
                AuthorizationRequestUrlParameters
                    .builder(redirectUri, Collections.singleton(scope))
                    .build()
            ).toString();
        
        return authorizationUrl;
    }
    
    // 使用授权码获取令牌
    private IAuthenticationResult acquireToken(String authCode) 
        throws MalformedURLException, ExecutionException, InterruptedException {
        
        ConfidentialClientApplication app = ConfidentialClientApplication.builder(
                clientId, ClientCredentialFactory.createFromSecret(clientSecret))
                .authority("https://login.microsoftonline.com/" + tenantId)
                .build();
        
        AuthorizationCodeParameters parameters = AuthorizationCodeParameters.builder(
                authCode, 
                new URI(redirectUri)
            ).scopes(Collections.singleton(scope))
             .build();
        
        return app.acquireToken(parameters).get();
    }
    
    // 使用访问令牌获取用户信息
    private Map<String, Object> getUserInfo(String accessToken) {
        String graphEndpoint = "https://graph.microsoft.com/v1.0/me";
        
        // 使用HttpClient调用Graph API
        // 实际实现需要添加错误处理和JSON解析
        return fetchUserDataFromGraph(graphEndpoint, accessToken);
    }
    
    // 调用Microsoft Graph API的实现
    private Map<String, Object> fetchUserDataFromGraph(String endpoint, String accessToken) {
        // 这里使用HttpClient简化实现
        // 实际项目使用RestTemplate或WebClient
        
        HttpGet request = new HttpGet(endpoint);
        request.setHeader("Authorization", "Bearer " + accessToken);
        
        try (CloseableHttpClient httpClient = HttpClients.createDefault();
             CloseableHttpResponse response = httpClient.execute(request)) {
            
            String json = EntityUtils.toString(response.getEntity());
            return new Gson().fromJson(json, new TypeToken<Map<String, Object>>(){}.getType());
            
        } catch (Exception e) {
            throw new RuntimeException("Failed to fetch user info", e);
        }
    }
}
 

4. 安全配置类 (可选)

import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.jwk.source.RemoteJWKSet;
import com.nimbusds.jose.proc.JWSVerificationKeySelector;
import com.nimbusds.jose.proc.SecurityContext;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.proc.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.net.MalformedURLException;
import java.net.URL;

@Configuration
public class SecurityConfig {

    @Value("${azure.tenant-id}")
    private String tenantId;
    
    // 配置JWT验证器
    @Bean
    public ConfigurableJWTProcessor<SecurityContext> jwtProcessor() 
        throws MalformedURLException {
        
        // Azure AD JWKS端点
        String jwksUrl = String.format(
            "https://login.microsoftonline.com/%s/discovery/v2.0/keys", 
            tenantId
        );
        
        // 设置JWT处理器
        DefaultJWTProcessor<SecurityContext> jwtProcessor = 
            new DefaultJWTProcessor<>();
        
        // 配置JWK来源
        JWKSource<SecurityContext> keySource = 
            new RemoteJWKSet<>(new URL(jwksUrl));
        
        // 配置签名验证
        JWSAlgorithm expectedJWSAlg = JWSAlgorithm.RS256;
        JWSVerificationKeySelector<SecurityContext> keySelector = 
            new JWSVerificationKeySelector<>(expectedJWSAlg, keySource);
        
        jwtProcessor.setJWSKeySelector(keySelector);
        
        // 设置JWT声明验证器
        jwtProcessor.setJWTClaimsSetVerifier(new DefaultJWTClaimsVerifier<>(
            new JWTClaimsSet.Builder().build(),
            new HashSet<>(Arrays.asList("sub", "aud", "exp", "iat"))));
        
        return jwtProcessor;
    }
}
 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/diannao/85689.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# 数据库访问与ORM框架全面指南:从ADO.NET到Entity Framework Core

在现代应用开发中&#xff0c;数据持久化是核心需求之一。作为.NET生态系统中的主力语言&#xff0c;C#提供了丰富多样的数据库访问技术和工具。本文将全面探讨C#中的数据库访问方式&#xff0c;重点介绍三种主流ORM&#xff08;对象关系映射&#xff09;框架&#xff1a;Entit…

day19 leetcode-hot100-37(二叉树2)

104. 二叉树的最大深度 - 力扣&#xff08;LeetCode&#xff09; 1.深度优先遍历&#xff08;递归&#xff09;ps:不好理解&#xff0c;所以我一般不喜欢用递归 思路 典型算法&#xff0c;用递归求出高度&#xff0c;每次都是深度优先。 具体算法 /*** Definition for a bi…

【LLMs篇】13:LLaDA—大型语言扩散模型

栏目内容论文标题大型语言扩散模型 (Large Language Diffusion Models)核心思想提出LLaDA&#xff0c;一种基于扩散模型的LLM&#xff0c;通过前向掩码和反向预测过程建模语言分布&#xff0c;挑战自回归模型&#xff08;ARM&#xff09;在LLM领域的主导地位&#xff0c;并展示…

Deepfashion2 数据集使用笔记

目录 数据类别: 筛选类别数据: 验证筛选前2个类别: Deepfashion2 的解压码 数据类别: 类别含义: Class idx类别名称英文名称0短上衣short sleeve top1长上衣long sleeve top2短外套short sleeve outwear3长外套long sleeve outwear4裙子skirt5裤子trousers6连衣裙dre…

Java并发编程哲学系列汇总

文章目录 并发编程基础并发编程进阶并发编程实践 并发编程基础 Java并发编程基础小结 Java线程池知识点小结 详解JUC包下各种锁的使用 并发编程利器Java CAS原子类全解 深入理解Java中的final关键字 Java并发容器深入解析&#xff1a;HashMap与ArrayList线程安全问题及解…

git 之 stash

一、git stash&#xff1a;临时保存工作区修改 作用 将当前工作目录和暂存区的未提交修改保存到栈中&#xff0c;并恢复工作区到上一次提交的干净状态。 适用场景&#xff1a; 临时切换分支修复紧急 Bug拉取远程代码前清理工作区保存实验性代码避免生成无效提交 常用命令&am…

vxe-grid 双击行,打开expand的内容

1、官网api Vxe Table v4.6&#xff08;根据版本&#xff09; 要调用这个事件&#xff0c;双击单元格&#xff0c;我们打开type"expand"的内容 2、打开的事件toggleRowExpand 3、事件的说明 这个方法&#xff0c;会自动判断当前展开的状态&#xff0c;然后去触发相…

Java Stream 高级实战:并行流、自定义收集器与性能优化

一、并行流深度实战&#xff1a;大规模数据处理的性能突破 1.1 并行流的核心应用场景 在电商用户行为分析场景中&#xff0c;需要对百万级用户日志数据进行实时统计。例如&#xff0c;计算某时段内活跃用户数&#xff08;访问次数≥3次的用户&#xff09;&#xff0c;传统循环…

计算机系统结构-第5章-监听式协议

监听式协议******&#xff1a; 思想: 每个Cache除了包含物理存储器中块的数据拷贝之外&#xff0c;也保存着各个块的共享状态信息。 Cache通常连在共享存储器的总线上&#xff0c;当某个Cache需要访问存储器时&#xff0c;它会把请求放到总线上广播出去&#xff0c;其他各个C…

(c++)string的模拟实现

目录 1.构造函数 2.析构函数 3.扩容 1.reserve(扩容不初始化) 2.resize(扩容加初始化) 4.push_back 5.append 6. 运算符重载 1.一个字符 2.一个字符串 7 []运算符重载 8.find 1.找一个字符 2.找一个字符串 9.insert 1.插入一个字符 2.插入一个字符串 9.erase 10…

学习笔记(24): 机器学习之数据预处理Pandas和转换成张量格式[2]

学习笔记(24): 机器学习之数据预处理Pandas和转换成张量格式[2] 学习机器学习&#xff0c;需要学习如何预处理原始数据&#xff0c;这里用到pandas&#xff0c;将原始数据转换为张量格式的数据。 学习笔记(23): 机器学习之数据预处理Pandas和转换成张量格式[1]-CSDN博客 下面…

LeetCode 2297. 跳跃游戏 VIII(中等)

题目描述 给定一个长度为 n 的下标从 0 开始的整数数组 nums。初始位置为下标 0。当 i < j 时&#xff0c;你可以从下标 i 跳转到下标 j: 对于在 i < k < j 范围内的所有下标 k 有 nums[i] < nums[j] 和 nums[k] < nums[i] , 或者对于在 i < k < j 范围…

【前端】缓存相关

本知识页参考&#xff1a;https://zhuanlan.zhihu.com/p/586060532 1. 概述 1.1 应用场景 静态资源 场景&#xff1a;图片、CSS、JS 文件等静态资源实现&#xff1a;使用 HTTP 缓存控制头&#xff0c;或者利用 CDN 进行边缘缓存 数据缓存 场景&#xff1a;请求的返回结果实现…

猎板硬金镀层厚度:高频通信领域的性能分水岭

在 5G 基站、毫米波雷达等高频场景中&#xff0c;硬金镀层厚度的选择直接决定了 PCB 的信号完整性与长期可靠性。猎板硬金工艺&#xff1a; 1.8μm 金层搭配罗杰斯 4350B 基材的解决方案&#xff0c;在 10GHz 频段实现插入损耗&#xff1c;0.15dB/cm&#xff0c;较常规工艺降低…

第35次CCF计算机软件能力认证-5-木板切割

原题链接&#xff1a; TUOJ 我自己写的35分正确但严重超时的代码 #include <bits/stdc.h> using namespace std; int main() {int n, m, k;cin >> n >> m >> k;vector<unordered_map<int, int>> mp(2);int y;for (int i 1; i < n; …

【蓝桥杯】包子凑数

包子凑数 题目描述 小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有 NN 种蒸笼&#xff0c;其中第 ii 种蒸笼恰好能放 AiAi​ 个包子。每种蒸笼都有非常多笼&#xff0c;可以认为是无限笼。 每当有顾客想买 XX 个包子&#xff0c;卖包子的大叔就会迅速选出若干…

pikachu通关教程-目录遍历漏洞(../../)

目录遍历漏洞也可以叫做信息泄露漏洞、非授权文件包含漏洞等. 原理:目录遍历漏洞的原理比较简单&#xff0c;就是程序在实现上没有充分过滤用户输入的../之类的目录跳转符&#xff0c;导致恶意用户可以通过提交目录跳转来遍历服务器上的任意文件。 这里的目录跳转符可以是../…

[概率论基本概念4]什么是无偏估计

关键词&#xff1a;Unbiased Estimation 一、说明 对于无偏和有偏估计&#xff0c;需要了解其叙事背景&#xff0c;是指整体和抽样的关系&#xff0c;也就是说整体的叙事是从理论角度的&#xff0c;而估计器原理是从实践角度说事&#xff1b;为了表明概率理论&#xff08;不可…

面试题——计算机网络:HTTP和HTTPS的区别?

HTTP&#xff08;HyperText Transfer Protocol&#xff09;&#xff1a;作为互联网上应用最广泛的网络通信协议&#xff0c;HTTP是基于TCP/IP协议族的应用层协议。它采用标准的请求-响应模式进行通信&#xff0c;通过简洁的报文格式&#xff08;包含请求行、请求头、请求体等&a…

uni-app学习笔记十九--pages.json全局样式globalStyle设置

pages.json 页面路由 pages.json 文件用来对 uni-app 进行全局配置&#xff0c;决定页面文件的路径、窗口样式、原生的导航栏、底部的原生tabbar 等。 导航栏高度为 44px (不含状态栏)&#xff0c;tabBar 高度为 50px (不含安全区)。 它类似微信小程序中app.json的页面管理部…