mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-29 18:51:53 +08:00
完成 yudao-sso-demo-by-code 实现获得用户信息
This commit is contained in:
parent
b7b31f03d3
commit
fc7a6c782a
@ -20,14 +20,14 @@ import java.nio.charset.StandardCharsets;
|
|||||||
@Component
|
@Component
|
||||||
public class OAuth2Client {
|
public class OAuth2Client {
|
||||||
|
|
||||||
private static final String BASE_URL = "http://127.0.0.1:48080/admin-api/system/oauth2/";
|
private static final String BASE_URL = "http://127.0.0.1:48080/admin-api/system/oauth2";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 租户编号
|
* 租户编号
|
||||||
*
|
*
|
||||||
* 默认使用 1;如果使用别的租户,可以调整
|
* 默认使用 1;如果使用别的租户,可以调整
|
||||||
*/
|
*/
|
||||||
private static final Long TENANT_ID = 1L;
|
public static final Long TENANT_ID = 1L;
|
||||||
|
|
||||||
private static final String CLIENT_ID = "yudao-sso-demo-by-code";
|
private static final String CLIENT_ID = "yudao-sso-demo-by-code";
|
||||||
private static final String CLIENT_SECRET = "test";
|
private static final String CLIENT_SECRET = "test";
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
package cn.iocoder.yudao.ssodemo.client;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.ssodemo.client.dto.CommonResult;
|
||||||
|
import cn.iocoder.yudao.ssodemo.client.dto.user.UserInfoRespDTO;
|
||||||
|
import cn.iocoder.yudao.ssodemo.framework.core.LoginUser;
|
||||||
|
import cn.iocoder.yudao.ssodemo.framework.core.SecurityUtils;
|
||||||
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
|
import org.springframework.http.*;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OAuth 2.0 客户端
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class UserClient {
|
||||||
|
|
||||||
|
private static final String BASE_URL = "http://127.0.0.1:48080/admin-api//system/oauth2/user";
|
||||||
|
|
||||||
|
// @Resource // 可优化,注册一个 RestTemplate Bean,然后注入
|
||||||
|
private final RestTemplate restTemplate = new RestTemplate();
|
||||||
|
|
||||||
|
public CommonResult<UserInfoRespDTO> getUser() {
|
||||||
|
// 1.1 构建请求头
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||||
|
headers.set("tenant-id", OAuth2Client.TENANT_ID.toString());
|
||||||
|
addTokenHeader(headers);
|
||||||
|
// 1.2 构建请求参数
|
||||||
|
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||||
|
|
||||||
|
// 2. 执行请求
|
||||||
|
ResponseEntity<CommonResult<UserInfoRespDTO>> exchange = restTemplate.exchange(
|
||||||
|
BASE_URL + "/get",
|
||||||
|
HttpMethod.GET,
|
||||||
|
new HttpEntity<>(body, headers),
|
||||||
|
new ParameterizedTypeReference<CommonResult<UserInfoRespDTO>>() {}); // 解决 CommonResult 的泛型丢失
|
||||||
|
Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功");
|
||||||
|
return exchange.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addTokenHeader(HttpHeaders headers) {
|
||||||
|
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||||
|
Assert.notNull(loginUser, "登录用户不能为空");
|
||||||
|
headers.add("Authorization", "Bearer " + loginUser.getAccessToken());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
package cn.iocoder.yudao.ssodemo.client.dto.user;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得用户基本信息 Response dto
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class UserInfoRespDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户编号
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户账号
|
||||||
|
*/
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户昵称
|
||||||
|
*/
|
||||||
|
private String nickname;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户邮箱
|
||||||
|
*/
|
||||||
|
private String email;
|
||||||
|
/**
|
||||||
|
* 手机号码
|
||||||
|
*/
|
||||||
|
private String mobile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户性别
|
||||||
|
*/
|
||||||
|
private Integer sex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户头像
|
||||||
|
*/
|
||||||
|
private String avatar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所在部门
|
||||||
|
*/
|
||||||
|
private Dept dept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所属岗位数组
|
||||||
|
*/
|
||||||
|
private List<Post> posts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class Dept {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门编号
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门名称
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 岗位
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class Post {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 岗位编号
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 岗位名称
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,21 +1,29 @@
|
|||||||
package cn.iocoder.yudao.ssodemo.controller;
|
package cn.iocoder.yudao.ssodemo.controller;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.ssodemo.client.UserClient;
|
||||||
|
import cn.iocoder.yudao.ssodemo.client.dto.CommonResult;
|
||||||
|
import cn.iocoder.yudao.ssodemo.client.dto.user.UserInfoRespDTO;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/user")
|
@RequestMapping("/user")
|
||||||
public class UserController {
|
public class UserController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private UserClient userClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得当前登录用户的基本信息
|
* 获得当前登录用户的基本信息
|
||||||
*
|
*
|
||||||
* @return TODO
|
* @return 用户信息;注意,实际项目中,最好创建对应的 ResponseVO 类,只返回必要的字段
|
||||||
*/
|
*/
|
||||||
@GetMapping("/get")
|
@GetMapping("/get")
|
||||||
public String getUser() {
|
public CommonResult<UserInfoRespDTO> getUser() {
|
||||||
return "";
|
return userClient.getUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,4 +29,9 @@ public class LoginUser {
|
|||||||
*/
|
*/
|
||||||
private List<String> scopes;
|
private List<String> scopes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问令牌
|
||||||
|
*/
|
||||||
|
private String accessToken;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,102 @@
|
|||||||
|
package cn.iocoder.yudao.ssodemo.framework.core;
|
||||||
|
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全服务工具类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class SecurityUtils {
|
||||||
|
|
||||||
|
public static final String AUTHORIZATION_BEARER = "Bearer";
|
||||||
|
|
||||||
|
private SecurityUtils() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从请求中,获得认证 Token
|
||||||
|
*
|
||||||
|
* @param request 请求
|
||||||
|
* @param header 认证 Token 对应的 Header 名字
|
||||||
|
* @return 认证 Token
|
||||||
|
*/
|
||||||
|
public static String obtainAuthorization(HttpServletRequest request, String header) {
|
||||||
|
String authorization = request.getHeader(header);
|
||||||
|
if (!StringUtils.hasText(authorization)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int index = authorization.indexOf(AUTHORIZATION_BEARER + " ");
|
||||||
|
if (index == -1) { // 未找到
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return authorization.substring(index + 7).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得当前认证信息
|
||||||
|
*
|
||||||
|
* @return 认证信息
|
||||||
|
*/
|
||||||
|
public static Authentication getAuthentication() {
|
||||||
|
SecurityContext context = SecurityContextHolder.getContext();
|
||||||
|
if (context == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return context.getAuthentication();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前用户
|
||||||
|
*
|
||||||
|
* @return 当前用户
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static LoginUser getLoginUser() {
|
||||||
|
Authentication authentication = getAuthentication();
|
||||||
|
if (authentication == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return authentication.getPrincipal() instanceof LoginUser ? (LoginUser) authentication.getPrincipal() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得当前用户的编号,从上下文中
|
||||||
|
*
|
||||||
|
* @return 用户编号
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static Long getLoginUserId() {
|
||||||
|
LoginUser loginUser = getLoginUser();
|
||||||
|
return loginUser != null ? loginUser.getId() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前用户
|
||||||
|
*
|
||||||
|
* @param loginUser 登录用户
|
||||||
|
* @param request 请求
|
||||||
|
*/
|
||||||
|
public static void setLoginUser(LoginUser loginUser, HttpServletRequest request) {
|
||||||
|
// 创建 Authentication,并设置到上下文
|
||||||
|
Authentication authentication = buildAuthentication(loginUser, request);
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Authentication buildAuthentication(LoginUser loginUser, HttpServletRequest request) {
|
||||||
|
// 创建 UsernamePasswordAuthenticationToken 对象
|
||||||
|
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
|
||||||
|
loginUser, null, Collections.emptyList());
|
||||||
|
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||||
|
return authenticationToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -3,10 +3,6 @@ package cn.iocoder.yudao.ssodemo.framework.core;
|
|||||||
import cn.iocoder.yudao.ssodemo.client.OAuth2Client;
|
import cn.iocoder.yudao.ssodemo.client.OAuth2Client;
|
||||||
import cn.iocoder.yudao.ssodemo.client.dto.CommonResult;
|
import cn.iocoder.yudao.ssodemo.client.dto.CommonResult;
|
||||||
import cn.iocoder.yudao.ssodemo.client.dto.oauth2.OAuth2CheckTokenRespDTO;
|
import cn.iocoder.yudao.ssodemo.client.dto.oauth2.OAuth2CheckTokenRespDTO;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
@ -17,7 +13,6 @@ import javax.servlet.ServletException;
|
|||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Token 过滤器,验证 token 的有效性
|
* Token 过滤器,验证 token 的有效性
|
||||||
@ -35,13 +30,13 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
||||||
FilterChain filterChain) throws ServletException, IOException {
|
FilterChain filterChain) throws ServletException, IOException {
|
||||||
// 1. 获得访问令牌
|
// 1. 获得访问令牌
|
||||||
String token = obtainAuthorization(request);
|
String token = SecurityUtils.obtainAuthorization(request, "Authentication");
|
||||||
if (StringUtils.hasText(token)) {
|
if (StringUtils.hasText(token)) {
|
||||||
// 2. 基于 token 构建登录用户
|
// 2. 基于 token 构建登录用户
|
||||||
LoginUser loginUser = buildLoginUserByToken(token);
|
LoginUser loginUser = buildLoginUserByToken(token);
|
||||||
// 3. 设置当前用户
|
// 3. 设置当前用户
|
||||||
if (loginUser != null) {
|
if (loginUser != null) {
|
||||||
setLoginUser(loginUser, request);
|
SecurityUtils.setLoginUser(loginUser, request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,50 +53,12 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
}
|
}
|
||||||
// 构建登录用户
|
// 构建登录用户
|
||||||
return new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType())
|
return new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType())
|
||||||
.setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes());
|
.setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes())
|
||||||
|
.setAccessToken(accessToken.getAccessToken());
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
// 校验 Token 不通过时,考虑到一些接口是无需登录的,所以直接返回 null 即可
|
// 校验 Token 不通过时,考虑到一些接口是无需登录的,所以直接返回 null 即可
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 从请求 Header 中,获得访问令牌
|
|
||||||
*
|
|
||||||
* @param request 请求
|
|
||||||
* @return 访问令牌
|
|
||||||
*/
|
|
||||||
private static String obtainAuthorization(HttpServletRequest request) {
|
|
||||||
String authorization = request.getHeader("Authentication");
|
|
||||||
if (!StringUtils.hasText(authorization)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
int index = authorization.indexOf("Bearer ");
|
|
||||||
if (index == -1) { // 未找到
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return authorization.substring(index + 7).trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置当前用户
|
|
||||||
*
|
|
||||||
* @param loginUser 登录用户
|
|
||||||
* @param request 请求
|
|
||||||
*/
|
|
||||||
private static void setLoginUser(LoginUser loginUser, HttpServletRequest request) {
|
|
||||||
// 创建 Authentication,并设置到上下文
|
|
||||||
Authentication authentication = buildAuthentication(loginUser, request);
|
|
||||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Authentication buildAuthentication(LoginUser loginUser, HttpServletRequest request) {
|
|
||||||
// 创建 UsernamePasswordAuthenticationToken 对象
|
|
||||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
|
|
||||||
loginUser, null, Collections.emptyList());
|
|
||||||
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
|
||||||
return authenticationToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
alert('获得个人信息失败,原因:' + result.msg)
|
alert('获得个人信息失败,原因:' + result.msg)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$('nicknameSpan').html(result.data.nickname);
|
$('#nicknameSpan').html(result.data.nickname);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@ -57,8 +57,8 @@
|
|||||||
|
|
||||||
<!-- 情况二:已登录:1)展示用户信息;2)刷新访问令牌;3)退出登录 -->
|
<!-- 情况二:已登录:1)展示用户信息;2)刷新访问令牌;3)退出登录 -->
|
||||||
<div id="yesLoginDiv" style="display: none">
|
<div id="yesLoginDiv" style="display: none">
|
||||||
您已登录!点击 <a href="#" onclick="ssoLogin()">退出 </a> 系统 <br />
|
您已登录!<button>退出登录</button> <br />
|
||||||
昵称:<span id="nicknameSpan"> 加载中... </span> <br />
|
昵称:<span id="nicknameSpan"> 加载中... </span> <button>修改昵称</button> <br />
|
||||||
访问令牌:<span id="accessTokenSpan"> 加载中... </span> <br />
|
访问令牌:<span id="accessTokenSpan"> 加载中... </span> <br />
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
Loading…
Reference in New Issue
Block a user