Commit f05cb559 authored by maqing's avatar maqing

垂直越权

parent addacedb
...@@ -32,7 +32,12 @@ public interface AuthConstants { ...@@ -32,7 +32,12 @@ public interface AuthConstants {
/** /**
* Redis缓存权限规则key * Redis缓存权限规则key
*/ */
String PERMISSION_ROLES_interface_KEY = "ltc:auth:permission:interface"; String PERMISSION_RESOURCE_INTERFACE_KEY = "ltc:resource:interface";
/**
* Redis缓存权限规则key
*/
String PERMISSION_ROLES_RESOURCE_KEY = "ltc:roles:resource";
/** /**
......
...@@ -51,11 +51,12 @@ public class ResourceServerConfig { ...@@ -51,11 +51,12 @@ public class ResourceServerConfig {
http.oauth2ResourceServer().jwt() http.oauth2ResourceServer().jwt()
.jwtAuthenticationConverter(jwtAuthenticationConverter()); .jwtAuthenticationConverter(jwtAuthenticationConverter());
http.authorizeExchange() http.authorizeExchange()
.pathMatchers("/api/oauth/token","/oauth/*","/api/oauth/genKeyPair").permitAll() .pathMatchers("/api/oauth/token","/api.system/role/getRoleResource",
"/api.system/resource/getManinMenu","/oauth/*","/api/oauth/genKeyPair").permitAll()
.anyExchange().access(authorizationManager) .anyExchange().access(authorizationManager)
.and() .and()
.exceptionHandling() .exceptionHandling()
// 处理未授权 // 处理
.accessDeniedHandler(accessDeniedHandler()) .accessDeniedHandler(accessDeniedHandler())
//处理未认证 //处理未认证
.authenticationEntryPoint(authenticationEntryPoint()) .authenticationEntryPoint(authenticationEntryPoint())
......
...@@ -5,7 +5,9 @@ import cn.hutool.core.convert.Convert; ...@@ -5,7 +5,9 @@ import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.hungraim.ltc.constant.AuthConstants; import com.hungraim.ltc.constant.AuthConstants;
import com.hungraim.ltc.pojo.entity.system.SystemInterface;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.ListUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
...@@ -21,10 +23,7 @@ import org.springframework.util.AntPathMatcher; ...@@ -21,10 +23,7 @@ import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher; import org.springframework.util.PathMatcher;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.util.HashSet; import java.util.*;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/** /**
* 鉴权管理器 * 鉴权管理器
...@@ -74,41 +73,38 @@ public class AuthorizationManager implements ReactiveAuthorizationManager<Author ...@@ -74,41 +73,38 @@ public class AuthorizationManager implements ReactiveAuthorizationManager<Author
return Mono.just(new AuthorizationDecision(false)); return Mono.just(new AuthorizationDecision(false));
} }
Mono<AuthorizationDecision> authorizationDecisionMono = mono.filter(Authentication::isAuthenticated)
// 从缓存取资源权限角色关系列表 .flatMapIterable(Authentication::getAuthorities)
Map<Object, Object> permissionRoles = redisTemplate.opsForHash().entries(AuthConstants.PERMISSION_ROLES_KEY); .map(GrantedAuthority::getAuthority)
Iterator<Object> iterator = permissionRoles.keySet().iterator(); .any(roleId -> {
// 请求路径匹配到的资源需要的角色权限集合authorities统计 // roleId是请求用户的角色(格式:ROLE_{roleId}),authorities是请求资源所需要角色的集合
Set<String> authorities = new HashSet<>(); log.info("访问路径:{}", path);
while (iterator.hasNext()) { log.info("用户角色信息:{}", roleId);
String pattern = (String) iterator.next(); //如果是管理员 直接放行
if (pathMatcher.match(pattern, path)) { if ("ROLE_0".equals(roleId)) {
authorities.addAll(Convert.toList(String.class, permissionRoles.get(pattern))); return true;
} }
} String[] splitpath = path.split("/");
log.info("require authorities:{}", authorities); String pathNew = "/" + splitpath[1] + "/" + splitpath[2] + "/*";
Set<String> authorities = new HashSet<>();
// 认证通过且角色匹配的用户可访问当前路径 Map<String, List<Long>> rolesResources = redisTemplate.opsForHash().entries(AuthConstants.PERMISSION_ROLES_RESOURCE_KEY);
// return mono.map(auth -> { Map<String, List<SystemInterface>> interfaces = redisTemplate.opsForHash().entries(AuthConstants.PERMISSION_RESOURCE_INTERFACE_KEY);
// return new AuthorizationDecision(true); List<Long> resources = rolesResources.get(roleId);
// }).defaultIfEmpty(new AuthorizationDecision(false)); for (Long resource : resources) {
List<SystemInterface> systemInterfaces = interfaces.get(resource.toString());
return mono if (systemInterfaces != null && systemInterfaces.size() > 0) {
.filter(Authentication::isAuthenticated) for (SystemInterface iter : systemInterfaces) {
.flatMapIterable(Authentication::getAuthorities) if (pathMatcher.match(iter.getInterfaceUrl(), pathNew)) {
.map(GrantedAuthority::getAuthority) authorities.addAll(Convert.toList(String.class, roleId));
.any(roleId -> { }
// roleId是请求用户的角色(格式:ROLE_{roleId}),authorities是请求资源所需要角色的集合 }
log.info("访问路径:{}", path); }
log.info("用户角色信息:{}", roleId); }
log.info("资源需要权限authorities:{}", authorities); log.info("资源需要权限authorities:{}", authorities);
//如果是管理员 直接放行 return authorities.contains(roleId);
if ("ROLE_0".equals(roleId)) { })
return true; .map(AuthorizationDecision::new)
} .defaultIfEmpty(new AuthorizationDecision(false));
return authorities.contains(roleId); return authorizationDecisionMono;
})
.map(AuthorizationDecision::new)
.defaultIfEmpty(new AuthorizationDecision(false));
} }
} }
...@@ -24,6 +24,6 @@ public class InitResourceInterfaceCacheRunner implements CommandLineRunner { ...@@ -24,6 +24,6 @@ public class InitResourceInterfaceCacheRunner implements CommandLineRunner {
@Override @Override
public void run(String... args){ public void run(String... args){
systemInterfaceService.refreshResourceInterfaceCache(); systemInterfaceService.listResourceInterface();
} }
} }
...@@ -2,6 +2,7 @@ package com.hungraim.ltc.system.dao; ...@@ -2,6 +2,7 @@ package com.hungraim.ltc.system.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hungraim.ltc.pojo.entity.system.SystemInterface; import com.hungraim.ltc.pojo.entity.system.SystemInterface;
import com.hungraim.ltc.pojo.entity.system.SystemResource;
import org.apache.ibatis.annotations.*; import org.apache.ibatis.annotations.*;
import java.util.List; import java.util.List;
...@@ -13,17 +14,14 @@ import java.util.List; ...@@ -13,17 +14,14 @@ import java.util.List;
@Mapper @Mapper
public interface SystemInterfaceMapper extends BaseMapper<SystemInterface> { public interface SystemInterfaceMapper extends BaseMapper<SystemInterface> {
@Select("SELECT a.INTERFACE_URL FROM " + @Select("SELECT a.INTERFACE_ID,a.INTERFACE_URL FROM LTC_INTERFACE a,LTC_RESOURCE_INTERFACE e where a.INTERFACE_ID=e.INTERFACE_ID and e.RESOURCE_ID=#{resourceId}")
"LTC_INTERFACE a where a.INTERFACE_ID= #{interfaceId}") List<SystemInterface> listInterface(Long resourceId);
List<String> listInterface(long interfaceId);
@Select("select b.ROLE_ID from LTC_ROLE b")
/** List<Long> listRole();
* 根据资源id查找接口id
* @Select("select c.RESOURCE_ID from LTC_ROLE_RESOURCE c WHERE c.ROLE_ID=#{roleId}")
* @return 角色id List<Long> listRoleResource(Long roleId);
*/
@Select("SELECT INTERFACE_ID FROM LTC_RESOURCE_INTERFACE")
List<Long> listRI();
} }
...@@ -8,13 +8,8 @@ import java.util.Map; ...@@ -8,13 +8,8 @@ import java.util.Map;
public interface ISystemInterfaceService { public interface ISystemInterfaceService {
/** /**
* 将mysql中的接口资源关系缓存到redis中
*/
void refreshResourceInterfaceCache();
/**
* 查询所有资源对应的接口 * 查询所有资源对应的接口
* @return list * @return list
*/ */
List<String> listResourceInterface(Long resourceId); void listResourceInterface();
} }
...@@ -10,43 +10,53 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -10,43 +10,53 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.HashMap; import java.util.*;
import java.util.List;
import java.util.Map;
/**
* @author mq
*/
@Service @Service
@Slf4j @Slf4j
public class SystemInterfaceServiceImpl extends ServiceImpl<SystemInterfaceMapper, SystemInterface> implements ISystemInterfaceService { public class SystemInterfaceServiceImpl extends ServiceImpl<SystemInterfaceMapper, SystemInterface> implements ISystemInterfaceService {
private final SystemInterfaceMapper systemInterfaceMapper; private final SystemInterfaceMapper systemInterfaceMapper;
private final SystemResourceServiceImpl systemResourceService;
private final RedisTemplate redisTemplate; private final RedisTemplate redisTemplate;
@Autowired @Autowired
public SystemInterfaceServiceImpl(SystemInterfaceMapper systemInterfaceMapper, RedisTemplate redisTemplate) { public SystemInterfaceServiceImpl(SystemInterfaceMapper systemInterfaceMapper, SystemResourceServiceImpl systemResourceService, RedisTemplate redisTemplate) {
this.systemInterfaceMapper = systemInterfaceMapper; this.systemInterfaceMapper = systemInterfaceMapper;
this.systemResourceService = systemResourceService;
this.redisTemplate = redisTemplate; this.redisTemplate = redisTemplate;
} }
@Override @Override
public void refreshResourceInterfaceCache() { public void listResourceInterface() {
try{ try {
redisTemplate.delete(AuthConstants.PERMISSION_ROLES_interface_KEY); redisTemplate.delete(AuthConstants.PERMISSION_RESOURCE_INTERFACE_KEY);
Map<String, List<String> > map = new HashMap<>(); redisTemplate.delete(AuthConstants.PERMISSION_ROLES_RESOURCE_KEY);
List<Long> interfaceIds = systemInterfaceMapper.listRI(); Map<String, List<Long>> roleResourcesMap = new TreeMap<>();
for (Long interfaceId:interfaceIds){ Map<String, List<SystemInterface>> stringStringHashMap = new HashMap<>();
List<String> systemInterfaces = this.listResourceInterface(interfaceId); List<Long> roles = systemInterfaceMapper.listRole();
map.put(interfaceId.toString(),systemInterfaces); String roleId;
for (Long role : roles) {
List<Long> roleResources = systemInterfaceMapper.listRoleResource(role);
//保存资源和接口
for (Long roleResource:roleResources){
List<SystemInterface> systemInterfaces=systemInterfaceMapper.listInterface(roleResource);
stringStringHashMap.put(roleResource.toString(),systemInterfaces);
}
// 转换 roles -> ROLE_{roleId}
roleId=AuthConstants.AUTHORITY_PREFIX + role;
//保存角色和资源
roleResourcesMap.put(roleId,roleResources);
} }
redisTemplate.opsForHash().putAll(AuthConstants.PERMISSION_ROLES_interface_KEY, map); redisTemplate.opsForHash().putAll(AuthConstants.PERMISSION_ROLES_RESOURCE_KEY, roleResourcesMap);
redisTemplate.opsForHash().putAll(AuthConstants.PERMISSION_RESOURCE_INTERFACE_KEY, stringStringHashMap);
}catch (RuntimeException e){ }catch (RuntimeException e){
e.printStackTrace(); e.printStackTrace();
} }
} }
@Override
public List<String> listResourceInterface(Long interfaceId) {
return systemInterfaceMapper.listInterface(interfaceId);
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment