tim*_*ive 6 java spring spring-security spring-boot spring-security-oauth2
我的API中的主要数据信息和信息链接到项目(实体),密码流的好方法是什么:管理与具有spring security和OAuth2的项目链接的特定权限?
在这个应用程序中,您有5个微服务:
缩放权限:
每个用户可以拥有多个项目,并且可以拥有每个项目的权限:
我有很多想法,但我不确定我是否有好的方法:
使用案例:我想要终止端点:
http://catalog-service/{project_key}/catalogs
Run Code Online (Sandbox Code Playgroud)
只有拥有项目{project_key}权限VIEW_CATALOG或MANAGE_CATALOG的用户才能列出项目中的所有目录
我的第一个想法是:使用预授权来使用ProjectAccessExpression
CatalogController.java
@Controller
public class CatalogController {
@PreAuthorize("@projectAccessExpression.hasPermission(#projectKey, 'manageCatalog', principal)" +
" or @projectAccessExpression.hasPermission(#projectKey, 'viewCatalog', principal)")
@RequestMapping(
value = "/{projectKey}/catalogs",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE
)
public @ResponseBody List<Catalog> findByProject(@PathVariable("projectKey") String projectKey) {
return catalogService.find();
}
}
Run Code Online (Sandbox Code Playgroud)
ProjectAccessExpression.java
@Component
public class ProjectAccessExpression {
private RestTemplate restTemplate;
public boolean havePermission(String projectKey, String permission , String username) {
Boolean havePermission = restTemplate.getForObject(String.format("http://uaa-service/permission/check?project=%1&permission=%2&username=%3",
projectKey, permission, username
), Boolean.class);
return havePermission;
}
}
Run Code Online (Sandbox Code Playgroud)
不方便的是:每次都需要拨打UAA服务
第二个想法:使用USER_ROLE
使用user_role
SHOP1是SHOP2是projectKey
不方便:我不确定,但如果用户更改权限,我需要撤销所有令牌关联
第三个想法:在身份验证blob中添加特定权限
我不知道如何存储......
并在控制器中注释:
@PreAuthorize("@ProjectAccessExpression.hasPermission(authentication, 'manageCatalog||viewCatalog', #projectKey)
Run Code Online (Sandbox Code Playgroud)
不方便:第二个想法同样不方便
这个解决方案我使用并且工作正常
** 1 - 用户签名时加载业务逻辑安全性 **
此示例查找具有角色的用户并保留在数据库中,并添加所有依赖于角色的项目。操作后,我拥有 GrantedAuthority 的身份验证令牌:ROLE_USER、ROLE_MANAGE_CATALOG:project1、ROLE_VIEW_PROFILE:project1、ROLE_MANAGE_PROJECT:project2,...
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<User> user = userService.findByLogin(username);
if (!user.isPresent()) {
Object args[] = {username};
throw new UsernameNotFoundException(
messageSource.getMessage("user.notexist", args, "User {0} doesn't not exist", LocaleContextHolder.getLocale())
);
}
if (!user.get().isActivated()) {
//throw new UserNotActivatedException(String.format("User %s was not activated!", username));
Object args[] = {username};
throw new UserNotActivatedException(
messageSource.getMessage("user.notactivated", args, "User {0} was not activated", LocaleContextHolder.getLocale()));
}
//Here implement your proper logic
//Add busness logic security Roles
// eg ROLE_MANAGE_PROJECT:{project_key}, ROLE_MANAGE_CATALOG:{project_key}
List<Role> bRoles = projectService.getRolesForUser(username)
user.get().getRoles().addAll(
bRoles
);
UserRepositoryUserDetails userDetails = new UserRepositoryUserDetails(user.get());
return userDetails;
}
}
Run Code Online (Sandbox Code Playgroud)
** 2 使用预授权表达式检查安全性 **
在本例中,只有具有此权限的用户才能执行此操作:
ROLE_MANAGE_PROJECT:{projectKey}
@PreAuthorize("@oauthUserAccess.hasPermission(authentication, '"+Constants.PP_MANAGE_PROJECT+"', #projectKey)") @RequestMapping( value="/projects/{projectKey}", method = RequestMethod.PUT, 生成 = MediaType.APPLICATION_JSON_VALUE )公共ResponseEntity updateProject(@PathVariable(“projectKey”)字符串projectKey,@Valid @RequestBody项目项目)
OauthUserAccess 类:
@Component("oauthUserAccess")
public class OauthUserAccess {
/**
* Check if it is the administrator of the application IMASTER
* @param authentication
* @param projectKey
* @return
*/
public boolean hasAdminPermission(OAuth2Authentication authentication, String projectKey) {
if(authentication.getOAuth2Request().getAuthorities().contains("ROLE_ADMIN")) return true;
return false;
}
/**
*
* @param authentication
* @param permissionType
* @param projectKey
* @return
*/
public boolean hasPermission(OAuth2Authentication authentication, String permissionType, String projectKey) {
if (!ProjectPermissionType.exist(permissionType) ||
projectKey.isEmpty() ||
!projectKey.matches(Constants.PROJECT_REGEX))
return false;
if (authentication.isClientOnly()) {
//TODO check scope permission
if(authentication.getOAuth2Request().getScope().contains(permissionType+":"+projectKey)) return true;
}
if (hasAdminPermission(authentication, projectKey)) return true;
String projectPermission = "ROLE_" + permissionType + ":" + projectKey;
String projectPermissionManage = "ROLE_" + permissionType.replace("VIEW", "MANAGE") + ":" + projectKey;
String manageProject = "ROLE_" + Constants.PP_MANAGE_PROJECT + ":" + projectKey;
Predicate<GrantedAuthority> p = r -> r.getAuthority().equals(projectPermission) || r.getAuthority().equals(projectPermissionManage) || r.getAuthority().equals(manageProject);
if (authentication.getAuthorities().stream().anyMatch(p)) {
return true;
};
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
3 - 优点/缺点
优势
业务逻辑权限仅在用户登录应用程序时加载,而不是每次加载,因此它是微服务架构的强大解决方案。
坏处
当权限更改时需要更新身份验证令牌或撤销令牌,否则当您更新用户的权限时,用户需要注销并登录。但是,如果没有此安全逻辑,您也会遇到同样的问题,例如当用户被禁用或启用时。
我的解决方案例如在控制器中使用:
newAuthorities = projectService.getRolesForUser(username);
UsernamePasswordAuthenticationToken newAuth = new UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(), newAuthorities);
OAuth2Authentication authentication = (OAuth2Authentication)SecurityContextHolder.getContext().getAuthentication();
Collection<OAuth2AccessToken> accessTokens = tokenStore.findTokensByUserName(principal.getName());
OAuth2Authentication auth2 = new OAuth2Authentication(authentication.getOAuth2Request(), newAuth);
accessTokens.forEach(token -> {
if (!token.isExpired()) {
tokenStore.storeAccessToken(token, auth2);
}
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1266 次 |
| 最近记录: |