📄 获取当前用户及扩展
内部资料,请刷新扫码登录
pigcloud
# 获取当前用户
SecurityUtils.getUser()
public PigxUser getUser(Authentication authentication) {
Object principal = authentication.getPrincipal();
if (principal instanceof PigUser) {
return (PigxUser) principal;
}
return null;
}
# 前端获取当前用户
import { useUserInfo } from '/@/stores/userInfo';
const user = useUserInfo().userInfos.user
# 资源服务器获取登录用户信息
pigx 4.6 版本中通过 OpaqueTokenIntrospector
实现改方法完成资源服务器中获取用户的内容
public class PigCustomOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
private final OAuth2AuthorizationService authorizationService;
@Override
public OAuth2AuthenticatedPrincipal introspect(String token) {
OAuth2Authorization oldAuthorization = authorizationService.findByToken(token, OAuth2TokenType.ACCESS_TOKEN);
if (Objects.isNull(oldAuthorization)) {
throw new InvalidBearerTokenException(token);
}
// 客户端模式默认返回
if (AuthorizationGrantType.CLIENT_CREDENTIALS.equals(oldAuthorization.getAuthorizationGrantType())) {
return new PigClientCredentialsOAuth2AuthenticatedPrincipal(oldAuthorization.getAttributes(),
AuthorityUtils.NO_AUTHORITIES, oldAuthorization.getPrincipalName());
}
Map<String, PigxUserDetailsService> userDetailsServiceMap = SpringContextHolder
.getBeansOfType(PigxUserDetailsService.class);
Optional<PigxUserDetailsService> optional = userDetailsServiceMap.values().stream()
.filter(service -> service.support(Objects.requireNonNull(oldAuthorization).getRegisteredClientId(),
oldAuthorization.getAuthorizationGrantType().getValue()))
.max(Comparator.comparingInt(Ordered::getOrder));
UserDetails userDetails = null;
try {
Object principal = Objects.requireNonNull(oldAuthorization).getAttributes().get(Principal.class.getName());
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = (UsernamePasswordAuthenticationToken) principal;
Object tokenPrincipal = usernamePasswordAuthenticationToken.getPrincipal();
userDetails = optional.get().loadUserByUser((PigxUser) tokenPrincipal);
}
catch (UsernameNotFoundException notFoundException) {
log.warn("用户不不存在 {}", notFoundException.getLocalizedMessage());
throw notFoundException;
}
catch (Exception ex) {
log.error("资源服务器 introspect Token error {}", ex.getLocalizedMessage());
}
return (PigxUser) userDetails;
}
}
整体逻辑如下
- 获取请求携带的 token 信息,然后去 redis 中查询据的客户端信息
- 然后选择对应的
userDetailsService
进行调用loadUserByUser
- 这样本次可以获取到对应的用户的最新信息,如果用户立即更新的权限信息也能及时获取到
- 最后返回 userdetail 供其他服务使用
# 使用总结
- 必须是资源服务器管理的接口 (带 token 请求,而不是对外暴露的接口)
如下接口通过 Inner 接口不鉴权,Restful pathVariable 风格的请求
@Inner
@GetMapping("/info/{username}")
根据上文原理说明 ,会给 spring security 添加一条 /info/*
的 忽略拦截规则,这样会导致只要是满足此规则的路径都会进行 token 校验,获取不到用户信息。 (这也就是为啥 SecurityUtils.getUser 为空的原因)
- 仅能从 User 中获取到以下字段
# 扩展字段
新增字段后请刷新 redis | flushdb
- 如上文所说,默认情况下只能获取到如上图的字段信息
# PigxUser 维护新的字段
public class PigxUser extends User {
//新字段
@Getter
private String newField;
//...原有字段
public PigxUser(String newField,...原有字段 ) {
super(...);
this.newField = newField;
//...原有字段
}
}
# 返回给 Spring Security OAuth
- PigxUserDetailsServiceImpl.getUserDetails
private UserDetails getUserDetails(R<UserInfo> result) {
// 构造security用户 , newField 是从 remoteUserService.info 查询返回 (UserInfo)
return new PigxUser(newField,...原有字段);
}