Spring Cloud实战 | 第七篇:完善ljf-admin服务,完成gateway基于角色权限认证

Spring Cloud实战 | 第七篇:完善ljf-admin服务,完成gateway基于角色权限认证

1、ljf-admin添加接口getUserDTOByUsername

/**
* @description: 获取userDTO
* @author: lijinfeng
* @date: 2021/12/14
* @param: [username]
* @return: com.ljf.common.base.vo.Result<com.ljf.admin.api.DTO.UserDTO>
*/
@GetMapping("/getUserDTOByUsername")
public Result<UserDTO> getUserDTOByUsername(@RequestParam String username){
//根据username获取SysUser对象
    LambdaQueryWrapper<SysUser> userQueryWrapper = new LambdaQueryWrapper<SysUser>()
            .eq(StringUtils.hasText(username), SysUser::getUsername,username);
    SysUser user = sysUserService.getOne(userQueryWrapper);
    log.info("获取user:"+user);
    if (ObjectUtils.isEmpty(user))
        return Result.error(ResultEnum.USER_NO_EXIST);
//根据userID获取SysUserRole对象
    LambdaQueryWrapper<SysUserRole> serRoleQueryWrapper = new LambdaQueryWrapper<SysUserRole>()
            .eq(SysUserRole::getUserId,user.getId());
    List<SysUserRole> sysUserRoleList = sysUserRoleService.list(serRoleQueryWrapper);
    log.info("获取用户角色关系sysUserRoleList:"+sysUserRoleList);
    if (sysUserRoleList.size() == 0)
        return Result.error(ResultEnum.USER_NO_EXIST_ROLE);
    UserDTO userDTO = new UserDTO(user);
    userDTO.setRoleIds(sysUserRoleList.stream().map(SysUserRole::getRoleId).collect(Collectors.toList()));
//根据roleId获取role对象
    List<SysRole> roleList =  sysRoleService.listByIds(userDTO.getRoleIds());
    log.info("获取用户角色roleList:"+roleList);


    userDTO.setRoles(roleList.stream().map(SysRole::getCode).collect(Collectors.toList()));
    userDTO.setRoleNames(roleList.stream().map(SysRole::getName).collect(Collectors.toList()));
    return Result.success(userDTO);


}

2、ljf-admin-api 添加feign接口

@GetMapping("/api/v1/admin/user/getUserDTOByUsername")
Result<UserDTO> getUserDTOByUsername(@RequestParam("username") String username);
3、ljf-auth修改UserDetailsServiceImpl类,完善认证登录用户信息
/**
* 【重要】从数据库获取用户信息,用于和前端传过来的用户信息进行密码判读
*/
@Service
@Slf4j
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private UserAdminFeign userAdminFeign;
    @Autowired
    private OAuthClientFeign oAuthClientFeign;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        String clientId = JwtUtils.getAuthClientId();
        Result<UserDTO> result;
        OAuthUserDetails oauthUserDetails = null;
        OauthClientDetails oauthClientDetails = oAuthClientFeign.getOAuthClientById(clientId).getData();
        if (!ObjectUtils.isEmpty(oauthClientDetails)) {
            result = userAdminFeign.getUserDTOByUsername(username);
            if (ResultEnum.SUCCESS.getCode().equals(result.getCode())) {
                UserDTO userDTO = result.getData();
                oauthUserDetails = new OAuthUserDetails(userDTO);
                System.out.println("ljf-auth:-----------------oauthUserDetails.toString():"+oauthUserDetails.toString());
            }
        } else {
            throw new NoSuchClientException("该clientId不存在: " + clientId);
        }


        if (oauthUserDetails == null || oauthUserDetails.getId() == null) {
            throw new UsernameNotFoundException(ResultEnum.USER_NO_EXIST.getMessage());
        } else if (!oauthUserDetails.isEnabled()) {
            throw new DisabledException("该账户已被禁用!");
        } else if (!oauthUserDetails.isAccountNonLocked()) {
            throw new LockedException("该账号已被锁定!");
        } else if (!oauthUserDetails.isAccountNonExpired()) {
            throw new AccountExpiredException("该账号已过期!");
        }
        return oauthUserDetails;
    }
}

4、修改ljf-gateway的ResourceServerConfig类

重新定义权限管理器

http.oauth2ResourceServer()
        .jwt()
        .jwtAuthenticationConverter(jwtAuthenticationConverter())//重新定义权限管理器
        .publicKey(rsaPublicKey());// 本地获取公钥

添加beanjwtAuthenticationConverter()

/**
* @return
* @link https://blog.youkuaiyun.com/qq_24230139/article/details/105091273
* ServerHttpSecurity没有将jwt中authorities的负载部分当做Authentication
* 需要把jwt的Claim中的authorities加入
* 方案:重新定义权限管理器,默认转换器JwtGrantedAuthoritiesConverter
*/
@Bean
public Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> jwtAuthenticationConverter() {
    JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
//设置前缀,默认为SCOPE_,级ROOT角色返回为SCOPE_ROOT,这里改成ROLE_ROOT
    jwtGrantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
//设置认证的属性为自定义OAuthUserDetails中的authorities属性
    jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("authorities");
    JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
    jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
    return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter);
}

5、添加鉴权管理器AuthorizationManager

/**
* @Auther: lijinfeng
* @Date: 2021/12/12
* @Description 描述:鉴权管理器
*/
@Component
@Slf4j
public class AuthorizationManager implements ReactiveAuthorizationManager<AuthorizationContext> {

    @Override
    public Mono<AuthorizationDecision> check(Mono<Authentication> mono, AuthorizationContext authorizationContext) {
        ServerHttpRequest request = authorizationContext.getExchange().getRequest();


        // 1. 对应跨域的预检请求直接放行
        if (request.getMethod() == HttpMethod.OPTIONS) {
            return Mono.just(new AuthorizationDecision(true));
        }

        log.info("判断用户JWT中携带的角色是否有能通过权限拦截的角色");
        // 判断用户JWT中携带的角色是否有能通过权限拦截的角色
        Mono<AuthorizationDecision> authorizationDecisionMono = mono
                .flatMapIterable(Authentication::getAuthorities)
                .map(GrantedAuthority::getAuthority)
                .any(authority -> {
                    log.info("用户权限(角色) : {}", authority); // ROLE_ROOT
                    // 截取ResourceServerConfig设置的自定义的ROLE_前缀
                    String role = authority.substring("ROLE_".length()); // ROOT
                    if ("ROOT".equals(role)) { // 如果是超级管理员则放行
                        return true;
                    }
                    // 其他角色暂时不让访问,以后添加条件后再具体判断
                    return false;
                })
                .map(AuthorizationDecision::new)
                .defaultIfEmpty(new AuthorizationDecision(false));
        return authorizationDecisionMono;
    }
}

6、测试root用户和admin用户

admin显示访问未授权,root用户正常访问
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

one one day

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值