具有角色的经过身份验证的用户的 Spring Security Java 配置

Posted

技术标签:

【中文标题】具有角色的经过身份验证的用户的 Spring Security Java 配置【英文标题】:Spring Security Java configuration for authenticated users with a role 【发布时间】:2016-02-13 21:17:18 【问题描述】:

我正在尝试使用带有 Spring Boot 的 Java 配置来配置 Spring Security。

我的 WebSecurityConfig 类有一个这样的配置方法

@Override
protected void configure(HttpSecurity http) throws Exception 
    http
        .authorizeRequests()
            .antMatchers("/", "/login", "/css/**", "/js/**", "/img/**", "/bootstrap/**" ).permitAll()
            .antMatchers("/individual", "/application", "/upload").hasRole("USER")
        .and()
            .formLogin()
                .loginPage("/login")
                .successHandler(successHandler);


我为未经身份验证的用户获得了登录页面,并且用户进行了身份验证。但是,当尝试访问 url /individual 时,我收到 403 错误,并且在日志中

2015-11-12 13:59:46.373 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/individual'; against '/'
2015-11-12 13:59:46.373 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/individual'; against '/login'
2015-11-12 13:59:46.373 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/individual'; against '/css/**'
2015-11-12 13:59:46.373 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/individual'; against '/js/**'
2015-11-12 13:59:46.374 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/individual'; against '/img/**'
2015-11-12 13:59:46.374 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/individual'; against '/bootstrap/**'
2015-11-12 13:59:46.374 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/individual'; against '/individual'
2015-11-12 13:59:46.374 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /individual; Attributes: [hasRole('ROLE_USER')]
2015-11-12 13:59:46.374 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@4c2eda81: Principal: org.springframework.security.core.userdetails.User@4c0ab982: Username: foo@bar.com; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffc7f0c: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 6E0BF830C070912EAC0050D1285D5CF9; Granted Authorities: USER
2015-11-12 13:59:46.374 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@6f192fd7, returned: -1
2015-11-12 13:59:46.386 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.a.ExceptionTranslationFilter     : Access is denied (user is not anonymous); delegating to AccessDeniedHandler

如果我将.hasRole("USER") 替换为.authenticated(),它会起作用并且用户会获得所需的页面,但不会检查任何角色。

我不知道如何指定用户必须经过身份验证并具有角色 USER。我查看了许多示例并尝试了许多组合,但我无法让它按预期工作。大多数示例还引用了较旧的基于 XML 的配置,我想避免这种情况。

我需要做什么来指定某些 URL 模式可以由具有某些角色的经过身份验证的用户访问?

根据要求,成功处理程序方法如下所示

@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication auth)
        throws IOException, ServletException 

    // Here we want to check whether the user has already started the process and redirect to the appropriate stage

    log.info("User  has been authenticated", auth.getName());

    if(auth.getName().equals("foo@bar.com"))
    
        redirectStrategy.sendRedirect(request, response, "/individual");
        return;
    


    redirectStrategy.sendRedirect(request, response, "/application");


请注意,根据代码中的 cmets,这是早期 WIP。我知道这是有效的,因为出现了日志消息,并且没有在 WebSecurity 类中进行角色检查,就会提供所需的页面。

编辑:注意到在提到 roleService.getDefaultRole() 的问题中有一个错字。这是一个错误,已更正。

【问题讨论】:

不要将角色指定为 USER,而应指定为 ROLE_USER。 查看下面的答案并发表评论,这会导致配置异常 显示您在用户登录时为用户分配角色的代码。 日志输出显示用户对象具有授予权限USER,所以我知道它正在分配给用户 根据我的回答,要么需要将 ROLE_USER 分配给 foo@bar.com,要么检查 hasAuthority 而不是 hasRole 【参考方案1】:

我已经解决了我自己的问题,部分归功于这里的各种建议让我以不同的方式研究它。还注意到 FrontierPsychiatrist 也提供了答案,但我在处理它时没有发现答案。

问题在于 Spring 可互换地指代 ROLES 和 AUTHORITIES。

在实现UserDetailsService 接口以允许Spring 从应用程序数据库加载用户记录后,我正在创建org.springframework.security.core.userdetails.User 的实例并设置授予的权限。可以在日志语句中看到用户对象具有 - Granted Authorities: USER,但随后我的安全配置正在检查角色,但失败了。简单地说,解决方案是检查权威。我还清理了配置,将要从安全性中忽略的 URL 模式与身份验证和授权分开。完整代码如下sn-p

@Override
public void configure(WebSecurity web) throws Exception 
    web
        .ignoring()
            .antMatchers( "/css/**", "/js/**", "/img/**", "/bootstrap/**");


@Override
protected void configure(HttpSecurity http) throws Exception 

    http
        .authorizeRequests()
            .antMatchers("/individual","/application", "/upload").hasAuthority("USER")
            .and()
        .formLogin()
            .loginPage("/login")
            .successHandler(successHandler)
            .permitAll()
            .and()
        .logout()
            .deleteCookies("remove")
            .logoutSuccessUrl("/login?logout")
            .permitAll();   

我真的希望这对其他人在使用 Spring 4 MVC 的基于 Java 的配置时有所帮助。

【讨论】:

【参考方案2】:

我认为您的登录用户 foo@bar.com 设置了错误的权限。在日志中,您可以看到权限是 ['USER'],但由于您使用的是角色,所以它应该是 ['ROLE_USER']。您在哪里定义 foo@bar.com 的权限?

否则尝试切换

.antMatchers("/individual", "/application", "/upload").hasRole("USER")

.antMatchers("/individual", "/application", "/upload").hasAuthority("USER")

【讨论】:

谢谢!在我自己弄清楚之前,我没有看到你的答案。文档对此并不清楚。【参考方案3】:

像这样修改你的配置。

http.authorizeRequests().antMatchers("/individual","/application", "/upload")
                .hasRole("USER").and().authorizeRequests().anyRequest()
                .authenticated().and()
        .formLogin()
            .loginPage("/login")
            .successHandler(successHandler);

如果您不希望对所有请求进行身份验证,您可以将 anyRequest() 方法替换为 antMatchers("/urls-goes-here")

【讨论】:

那行不通。 anyRequest().authenticated() 表示 /login 无法访问,导致重定向循环。删除这意味着所有页面都可以访问 在 antMatchers 中添加 url 模式而不是 anyRequest,然后在其上调用身份验证。我在帖子中提到过。【参考方案4】:

这里有一个教程,可以做你想要实现的东西:

http://www.jcombat.com/spring/custom-authentication-success-handler-with-spring-security

我猜你忘了在处理程序中设置会话属性:

    HttpSession session = request.getSession();
    session.setAttribute("uname", authUser.getUsername());  
    session.setAttribute("authorities", authentication.getAuthorities()); 

【讨论】:

Spring 透明地添加“ROLE_”以进行角色匹配。如果您查看示例,只需“USER”即可。 我试过了,但是你得到一个异常原因:java.lang.IllegalArgumentException:角色不应该以'ROLE_'开头,因为它是自动插入的。得到了“ROLE_USER” 好吧,我的错。休息看起来不错,您可以编辑您的原始帖子以包含您的自定义成功处理程序吗? 用教程链接更新了我的答案,请查看并告诉我们它是否有效 这会将检查角色的责任转移给成功处理程序,但仅在登录时。这不会在任何其他时间检查。 url 模式应始终受角色限制。

以上是关于具有角色的经过身份验证的用户的 Spring Security Java 配置的主要内容,如果未能解决你的问题,请参考以下文章

AWS - JavaScript - 具有经过身份验证的 Cognito 用户对 DynamoDB 的 CRUD 操作

存储/分配经过身份验证的用户的角色

WSO2IS/APIM:如何在自定义身份验证器中分配用户角色

Spring(引导)具有允许资源的安全预身份验证仍然经过身份验证

使用 google firebase 和 spring 进行身份验证

没有使用数据库的角色库的 Spring Security