[英]Access denied exception while trying to access the login page in spring security
我正在使用基于java的spring security。 我创建了自定义访问决策选民impl。
但是当我运行应用程序时,我无法打开登录页面,因为它说,访问被拒绝。
这是在我添加自定义访问决策选民impl之后发生的。 我想问题是由于自定义AccessDecisionVoter中的以下代码。
if(authentication instanceof AnonymousAuthenticationToken)
return ACCESS_DENIED;
但我需要这样,以便不检查未登录用户的权限。
它进入无限循环,登录页面,访问决策选民,访问被拒绝,登录页面等。
下面是spring安全配置代码。
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private AffirmativeBased accessDecisionManager;
@Bean
@Autowired
public AffirmativeBased accessDecisionManager(AccessDecisionVoterImpl accessDecisionVoter) {
List<AccessDecisionVoter<?>> accessDecisionVoters = new ArrayList<AccessDecisionVoter<?>>();
accessDecisionVoters.add(accessDecisionVoter);
AffirmativeBased accessDecisionManager = new AffirmativeBased(accessDecisionVoters);
return accessDecisionManager;
}
@Override
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder(){
PasswordEncoder passwordEncoder = new PasswordEncoder();
passwordEncoder.setStringDigester(stringDigester());
return passwordEncoder;
}
@Bean
public PooledStringDigester stringDigester() {
PooledStringDigester psd = new PooledStringDigester();
psd.setPoolSize(2);
psd.setAlgorithm("SHA-256");
psd.setIterations(1000);
psd.setSaltSizeBytes(16);
psd.setSaltGenerator(randomSaltGenerator());
return psd;
}
@Bean
public RandomSaltGenerator randomSaltGenerator() {
RandomSaltGenerator randomSaltGenerator = new RandomSaltGenerator();
return randomSaltGenerator;
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/static/**")
.antMatchers("/i18n/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/checkLogin")
.defaultSuccessUrl("/home")
.failureUrl("/login?login_error=1")
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login?isLoggedOut=1")
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
.permitAll()
.and()
.authorizeRequests()
.antMatchers("/login**").permitAll()
.antMatchers("/error**").permitAll()
.antMatchers("/checkLogin**").permitAll()
.anyRequest()
.authenticated()
.accessDecisionManager(accessDecisionManager)
.and()
.exceptionHandling()
.accessDeniedPage("/accessDenied")
.and()
.headers()
.frameOptions()
.disable()
.and()
.sessionManagement()
.invalidSessionUrl("/login")
.maximumSessions(1);
}
}
和我的自定义选民impl
@Component
public class AccessDecisionVoterImpl implements AccessDecisionVoter {
@Autowired
private ModuleService moduleService;
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
@Override
public boolean supports(Class clazz) {
return true;
}
@Override
public int vote(Authentication authentication, Object object, Collection collection) {
// i have given this so that if user is not logged in then should not check permission at all
if(authentication instanceof AnonymousAuthenticationToken)
return ACCESS_DENIED;
HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
String requestedOperation = request.getParameter("operation");
if (requestedOperation != null && !requestedOperation.isEmpty()){
String [] requestURISplit = request.getRequestURI().split("/");
String requestedModuleName = requestURISplit[2];
if(SecurityUtils.hasPermission(requestedModuleName, requestedOperation)){
return ACCESS_GRANTED;
}
} else {
return ACCESS_GRANTED;
}
return ACCESS_DENIED;
此外,当我从选民中删除以下行时,如果用户未登录并尝试访问受保护的页面,则会继续。 它应该已重定向到登录页面。
if(authentication instanceof AnonymousAuthenticationToken)
return ACCESS_DENIED;
这是我第一次尝试使用弹簧靴。 因此,我不确定所有的配置问题。
antMatchers的顺序有什么问题吗?
请帮忙。
AccessDecisionVoter.ACCESS_ABSTAIN
):如果选民无法做出决定(例如,用户未经授权,无法从请求上下文等获取模块) AccessDecisionVoter.ACCESS_GRANTED
):如果可以识别模块并且用户被授权 AccessDecisionVoter.ACCESS_DENIED
):如果可以识别模块并且用户未被授权 使用AccessDecisionManager
配置,您基本上可以取消基于URL的访问限制,例如:
http.authorizeRequests()
.antMatchers("/css/**", "/img/**", "/js/**", "/font/**").permitAll()
.antMatchers("/login**").permitAll()
.antMatchers("/error**").permitAll()
.antMatchers("/checkLogin**").permitAll()
.anyRequest()
.authenticated()
默认情况下,spring使用WebExpressionVoter
来实现此目的。 但是,如果至少有一个AccessDecisionVoter授予对资源的访问权限,则AffirmativeBased
AccessDecisionManager将授予访问权限(这可能不是您想要的)。 根据您的要求,包含WebExpressionVoter
的ConsensusBased
AccessDecisionManager将是最佳匹配。
@Bean
public AccessDecisionManager accessDecisionManager() {
List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList<>();
decisionVoters.add(new WebExpressionVoter());
decisionVoters.add(new ModuleAccessDecisionVoter());
ConsensusBased consensusBased = new ConsensusBased(decisionVoters);
// deny access if voters equally voted to allow and deny access
consensusBased.setAllowIfEqualGrantedDeniedDecisions(false);
return consensusBased;
}
您的AccessDecisionVoter
实现:
static class ModuleAccessDecisionVoter implements AccessDecisionVoter<FilterInvocation> {
public int vote(Authentication authentication, FilterInvocation object, Collection<ConfigAttribute> attributes) {
if (authentication == null || authentication instanceof AnonymousAuthenticationToken) {
return ACCESS_ABSTAIN;
}
// determine module and grant or deny access
// if module cannot be determined abstain from voting
String module = determineModule(object);
if (module != null) {
return isAccessGranted(module, authentication) ? ACCESS_GRANTED : ACCESS_DENIED
}
return ACCESS_ABSTAIN;
}
}
匿名访问应导致以下结果:
/login
:WebExpressionVoter: +1
,ModuleVoter: 0
- > 1
= ACCESS_GRANTED
/foo-module
:WebExpressionVoter: -1
,ModuleVoter: -1
- > -2
= ACCESS_DENIED
给定允许查看Foo
模块的用户应该产生以下结果:
/foo-module
:WebExpressionVoter: +1
,ModuleVoter: +1
- > 2
= ACCESS_GRANTED
/bar-module
:WebExpressionVoter: +1
(因为用户已通过身份验证),ModuleVoter: -1
- > 0
= ACCESS_DENIED
(因为ConsensusBased.setAllowIfEqualGrantedDeniedDecisions(false)
) 如果我正确读取此内容,您将尝试通过返回ACCESS_DENIED进行匿名身份验证来解决用户匿名登录的问题。 那不好。 删除该自定义代码,而不是在安全配置中执行此操作:
anyRequest().hasRole("USER")
然后,确保在用户登录时,他们具有所需的角色。
另一种方法是禁用匿名登录,这样您就不需要角色(长期不推荐这样做)。
http.anonymous().disable()
问题来自你的选民。 如果配置了相关的“ConfigAttribute”,您的选民应该允许匿名访问。 以下是您应该添加的内容(可能取决于您的Spring Security版本):
for (ConfigAttribute attribute : collection) {
if ("IS_AUTHENTICATED_ANONYMOUSLY".equals(attribute.getAttribute())) {
return ACCESS_GRANTED;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.