Spring 安全自定义 FilterInvocationSecurityMetadataSource 实现 403 禁止问题
Spring security custom FilterInvocationSecurityMetadataSource implementation 403 forbidden issue
简而言之,我正在尝试实现自定义 FilterInvocationSecurityMetadataSource,以便使用 spring 安全 5.0.6 和 secure/authorize 在我的 Web 应用程序中动态地 parts/URL 端点 Spring 启动 2.0.3.
问题是无论我使用什么角色,它总是给我禁用页面。
我用不同的角色名称尝试了几种方法,并且(相信我)我甚至在 spring security 5.0.6 书籍上搜索了整个互联网,但似乎没有任何效果。
这个问题可能类似于:Spring Security issue with securing URLs dynamically
下面是自定义FilterInvocationSecurityMetadataSource的相关部分
public class DbFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
public Collection<ConfigAttribute> getAttributes(Object object)
throws IllegalArgumentException {
FilterInvocation fi=(FilterInvocation)object;
String url=fi.getRequestUrl();
System.out.println("URL requested: " + url);
String[] stockArr = new String[]{"ROLE_ADMIN"};
return SecurityConfig.createList(stockArr);
}
下面是securitywebconfigAdapter自定义实现的相关部分
@Configuration
public class Security extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
public <O extends FilterSecurityInterceptor> O postProcess(
O fsi) {
FilterInvocationSecurityMetadataSource newSource = new DbFilterInvocationSecurityMetadataSource();
fsi.setSecurityMetadataSource(newSource);
return fsi;
}
})
.and()
.formLogin()
.permitAll();
}
在自定义 userDetails 权限的相关部分下方。
用户在数据库中具有角色:ROLE_ADMIN。
public class CustomUserDetails extends User implements UserDetails {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<String> dbRoles=new ArrayList<String>();
for (Role userRole : super.getRoles()) {
dbRoles.add(userRole.getType());
}
List<SimpleGrantedAuthority> authorities=new ArrayList<SimpleGrantedAuthority>();
for (String role : dbRoles) {
authorities.add(new SimpleGrantedAuthority(role));
}
return authorities;
}
我做错了什么??
如果需要更多代码,请在下方评论。
如果你有好书,我可以在下面学习 Spring 安全授权评论的这个动态部分。
谢谢!
我设法通过调试进入安全流程,似乎通过创建此 SecurityConfig class 的 ConfigAttributes 是 'culprit'
return SecurityConfig.createList(stockArr);
public static List<ConfigAttribute> createList(String... attributeNames) {
Assert.notNull(attributeNames, "You must supply an array of attribute names");
List<ConfigAttribute> attributes = new ArrayList(attributeNames.length);
String[] var2 = attributeNames;
int var3 = attributeNames.length;
for(int var4 = 0; var4 < var3; ++var4) {
String attribute = var2[var4];
attributes.add(new SecurityConfig(attribute.trim()));
}
return attributes;
}
上面是方法的实际实现,大家可以看看
attributes.add(new SecurityConfig(attribute.trim()));
这总是会创建一个 SecurityConfig 类型的实例。
在下方您可以实际看到决策是在何处以及如何做出的。
private WebExpressionConfigAttribute findConfigAttribute(Collection<ConfigAttribute> attributes) {
Iterator var2 = attributes.iterator();
ConfigAttribute attribute;
do {
if (!var2.hasNext()) {
return null;
}
attribute = (ConfigAttribute)var2.next();
} while(!(attribute instanceof WebExpressionConfigAttribute));
return (WebExpressionConfigAttribute)attribute;
}
所以为了让它真正 return 一个用于检查它的配置属性必须是 WebExpressionConfigAttribute 类型,因为这个
永远不会是这种情况
attributes.add(new SecurityConfig(attribute.trim()));
所以我修复它的方法是通过以下方式创建我自己的 accessDecisionManager
public class MyAccessDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException, InsufficientAuthenticationException {
if(configAttributes == null){
return ;
}
Iterator<ConfigAttribute> ite = configAttributes.iterator();
while(ite.hasNext()){
ConfigAttribute ca = ite.next();
String needRole = ((SecurityConfig)ca).getAttribute();
for(GrantedAuthority grantedAuthority : authentication.getAuthorities()){
if(needRole.trim().equals(grantedAuthority.getAuthority().trim())){
return;
}
}
}
throw new AccessDeniedException("Access is denied");
}
然后按上面的方式注册,现在用我的自定义设置 accessdecisionManager
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
public <O extends FilterSecurityInterceptor> O postProcess(
O fsi) {
FilterInvocationSecurityMetadataSource newSource = new DbFilterInvocationSecurityMetadataSource();
fsi.setSecurityMetadataSource(newSource);
fsi.setAccessDecisionManager(new MyAccessDecisionManager());
return fsi;
}
简而言之,我正在尝试实现自定义 FilterInvocationSecurityMetadataSource,以便使用 spring 安全 5.0.6 和 secure/authorize 在我的 Web 应用程序中动态地 parts/URL 端点 Spring 启动 2.0.3.
问题是无论我使用什么角色,它总是给我禁用页面。
我用不同的角色名称尝试了几种方法,并且(相信我)我甚至在 spring security 5.0.6 书籍上搜索了整个互联网,但似乎没有任何效果。
这个问题可能类似于:Spring Security issue with securing URLs dynamically
下面是自定义FilterInvocationSecurityMetadataSource的相关部分
public class DbFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
public Collection<ConfigAttribute> getAttributes(Object object)
throws IllegalArgumentException {
FilterInvocation fi=(FilterInvocation)object;
String url=fi.getRequestUrl();
System.out.println("URL requested: " + url);
String[] stockArr = new String[]{"ROLE_ADMIN"};
return SecurityConfig.createList(stockArr);
}
下面是securitywebconfigAdapter自定义实现的相关部分
@Configuration
public class Security extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
public <O extends FilterSecurityInterceptor> O postProcess(
O fsi) {
FilterInvocationSecurityMetadataSource newSource = new DbFilterInvocationSecurityMetadataSource();
fsi.setSecurityMetadataSource(newSource);
return fsi;
}
})
.and()
.formLogin()
.permitAll();
}
在自定义 userDetails 权限的相关部分下方。 用户在数据库中具有角色:ROLE_ADMIN。
public class CustomUserDetails extends User implements UserDetails {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<String> dbRoles=new ArrayList<String>();
for (Role userRole : super.getRoles()) {
dbRoles.add(userRole.getType());
}
List<SimpleGrantedAuthority> authorities=new ArrayList<SimpleGrantedAuthority>();
for (String role : dbRoles) {
authorities.add(new SimpleGrantedAuthority(role));
}
return authorities;
}
我做错了什么??
如果需要更多代码,请在下方评论。
如果你有好书,我可以在下面学习 Spring 安全授权评论的这个动态部分。
谢谢!
我设法通过调试进入安全流程,似乎通过创建此 SecurityConfig class 的 ConfigAttributes 是 'culprit'
return SecurityConfig.createList(stockArr);
public static List<ConfigAttribute> createList(String... attributeNames) {
Assert.notNull(attributeNames, "You must supply an array of attribute names");
List<ConfigAttribute> attributes = new ArrayList(attributeNames.length);
String[] var2 = attributeNames;
int var3 = attributeNames.length;
for(int var4 = 0; var4 < var3; ++var4) {
String attribute = var2[var4];
attributes.add(new SecurityConfig(attribute.trim()));
}
return attributes;
}
上面是方法的实际实现,大家可以看看
attributes.add(new SecurityConfig(attribute.trim()));
这总是会创建一个 SecurityConfig 类型的实例。
在下方您可以实际看到决策是在何处以及如何做出的。
private WebExpressionConfigAttribute findConfigAttribute(Collection<ConfigAttribute> attributes) {
Iterator var2 = attributes.iterator();
ConfigAttribute attribute;
do {
if (!var2.hasNext()) {
return null;
}
attribute = (ConfigAttribute)var2.next();
} while(!(attribute instanceof WebExpressionConfigAttribute));
return (WebExpressionConfigAttribute)attribute;
}
所以为了让它真正 return 一个用于检查它的配置属性必须是 WebExpressionConfigAttribute 类型,因为这个
永远不会是这种情况attributes.add(new SecurityConfig(attribute.trim()));
所以我修复它的方法是通过以下方式创建我自己的 accessDecisionManager
public class MyAccessDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException, InsufficientAuthenticationException {
if(configAttributes == null){
return ;
}
Iterator<ConfigAttribute> ite = configAttributes.iterator();
while(ite.hasNext()){
ConfigAttribute ca = ite.next();
String needRole = ((SecurityConfig)ca).getAttribute();
for(GrantedAuthority grantedAuthority : authentication.getAuthorities()){
if(needRole.trim().equals(grantedAuthority.getAuthority().trim())){
return;
}
}
}
throw new AccessDeniedException("Access is denied");
}
然后按上面的方式注册,现在用我的自定义设置 accessdecisionManager
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
public <O extends FilterSecurityInterceptor> O postProcess(
O fsi) {
FilterInvocationSecurityMetadataSource newSource = new DbFilterInvocationSecurityMetadataSource();
fsi.setSecurityMetadataSource(newSource);
fsi.setAccessDecisionManager(new MyAccessDecisionManager());
return fsi;
}