Spring Security hasRole()不起作用

时间:2015-06-11 17:58:11

标签: java spring spring-mvc spring-security thymeleaf

使用Spring Security&&amp ;;时遇到问题Thymeleaf,特别是在尝试使用hasRole表达式时。 ' admin'用户有一个角色' ADMIN'但hasRole('ADMIN')无论如何都会解析为假的

我的HTML:

1.<div sec:authentication="name"></div> <!-- works fine -->
2.<div sec:authentication="principal.authorities"></div> <!-- works fine -->

3.<div  sec:authorize="isAuthenticated()" >true</div> <!-- works fine -->
4.<span th:text="${#authorization.expression('isAuthenticated()')}"></span> <!-- works fine -->

5.<div th:text="${#vars.role_admin}"></div> <!--Works fine -->
6.<div  sec:authorize="${hasRole('ADMIN')}" > IS ADMIN </div> <!-- Doesnt work -->
7.<div  sec:authorize="${hasRole(#vars.role_admin)}" > IS ADMIN </div> <!-- Doesnt work -->
8.<div th:text="${#authorization.expression('hasRole(''ADMIN'')')} "></div> <!-- Doesnt work -->
9.<div th:text="${#authorization.expression('hasRole(#vars.role_admin)')}"></div> <!-- Doesnt work -->

结果:

1.admin
2.[ADMIN]
3.true
4.true
5.ADMIN
6."prints nothing because hasRole('ADMIN') resolves to false"
7."prints nothing because hasRole(#vars.role_admin) resolves to false"
8.false
9.false

我在security.xml文件中启用了 use-expressions

<security:http auto-config="true" use-expressions="true">

还包括我的配置中的SpringSecurityDialect

<bean id="templateEngine"
      class="org.thymeleaf.spring4.SpringTemplateEngine">
    <property name="templateResolver" ref="templateResolver" />  
    <property name="additionalDialects">
        <set>
            <bean class="org.thymeleaf.extras.springsecurity4.dialect.SpringSecurityDialect" />
        </set>
    </property>      
</bean>

我的pom.xml文件中所有必需的依赖项

<!--Spring security--> 
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-core</artifactId>
        <version>4.0.1.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>4.0.1.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
        <version>4.0.1.RELEASE</version>
    </dependency>        

    <!--Thymeleaf Spring Security-->
    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity4</artifactId>
        <version>2.1.2.RELEASE</version>
        <scope>compile</scope>
    </dependency>

Role.java

@Entity
@Table(name = "roles")

    public class Role implements Serializable {

        @Id
        @Enumerated(EnumType.STRING)
        private RoleType name;
        //... getters, setters
    }

角色类型

public enum RoleType {

    ADMIN 
}

User有一套Role s

为什么hasRole()无效?

感谢您的帮助,谢谢

解决方法

th:if="${#strings.contains(#authentication.principal.authorities,'ADMIN')}"

11 个答案:

答案 0 :(得分:71)

尝试在HTML标记内使用hasAuthority代替hasRole

sec:authorize="hasAuthority('ADMIN')"

答案 1 :(得分:12)

我有同样的问题从Spring Security 3.x升级到4.x.将hasRole()更改为hasAuthority()对我来说非常有用。

http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#el-common-built-in

答案 2 :(得分:6)

我必须做类似的事情,我需要验证用户角色。我在下面做了

android:targetActivity="com.example.study.MainActivity"

希望它有所帮助。

答案 3 :(得分:6)

你错过了一个概念:

  • 如果您使用ADMIN Enum,则ROLE_ADMIN必须ADMIN而不是hasAuthority('ADMIN')
  • 如果您使用ADMIN Enum,则ADMIN必须为hasRole()

在春季安全方面,hasAuthority()hasRole()相同,但Authority功能地图与ROLE_没有{{1}}前缀。

您可以在这篇文章中找到接受的答案:Difference between Role and GrantedAuthority in Spring Security

答案 4 :(得分:4)

我最近遇到了同样的问题。 你需要做的是:

  1. 在你的html中添加以下语句:

    <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"   xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
    
  2. (您可以根据您使用的内容在springsecurity4或springsecurity3之间进行更改。)

    1. 请确保您已将此资源添加到库中。我正在使用gradle,但你也可以使用Maven。

      compile 'org.thymeleaf.extras:thymeleaf-extras-springsecurity4:2.1.2.RELEASE'
      
    2. 在SpringWebConfiguration类或xml中,请确保为thymeleaf SpringSecurity添加方言: 我正在使用java类进行配置。

      @Bean
      public SpringTemplateEngine templateEngine() {
      SpringTemplateEngine templateEngine = new SpringTemplateEngine();
      templateEngine.setTemplateResolver(templateResolver());
      templateEngine.addDialect(new SpringSecurityDialect());
      return templateEngine;
      }
      
    3. 但你也可以定义为alexsource说: Spring security and Thymeleaf doesn't work

      我希望这适合你! 问候!

答案 5 :(得分:1)

参考官方文件。 http://www.thymeleaf.org/doc/articles/springsecurity.html

<div sec:authorize="hasRole('ROLE_ADMIN')">
  This content is only shown to administrators.
</div>
<div sec:authorize="hasRole('ROLE_USER')">
  This content is only shown to users.
</div>

如果没有${ ... }

,您可以按照以下方式尝试
<div sec:authorize="hasRole('ADMIN')">IS ADMIN</div>

我相信你没有用ROLE_作为前缀。如果是这样,可以添加前缀,如下所示

<div sec:authorize="hasRole('ROLE_ADMIN')">IS ADMIN</div>

答案 6 :(得分:1)

由于4.0 thymeleaf-extras-springsecurity4,我遇到了同样的问题。由于某些原因,spring-securitythymeleaf 4.0和2.x spring-security不兼容。 所以我将3.2.9.RELEASE版本降级为4.0,然后就开始工作了。 如果你仍然想使用spring-security thymeleaf-extras-springsecurity4,那么你可以尝试将3.0.0.RELEASE提升到thymeleaf3.0 verison到spring-security

或者如果您使用的是Spring启动应用程序,那么情况会变得更加棘手,那么剩下的唯一选择就是降级<!--Spring security--> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>3.2.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>3.2.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>3.2.9.RELEASE</version> </dependency> <!--Thymeleaf Spring Security--> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity4</artifactId> <version>2.1.2.RELEASE</version> <scope>compile</scope> </dependency> 或将Spring启动版本升级到1.4.x(仍然在BETA)

在您的特定情况下,进行以下pom更改应使hasRole正常工作

'recentreports'

答案 7 :(得分:0)

经过数周的反复试验,这对我有用:

根据https://mvnrepository.com/升级到最新版本

Spring Boot Starter Thymeleaf Extras Spring Security 5 Thymeleaf(用于Spring Boot)

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
        <version>2.3.0.RELEASE</version>
    </dependency>

真的不知道该版本的依赖项是否可以与其他版本很好地配合,但是目前(2020年5月19日)它对我有用。

希望它可以帮助某人

答案 8 :(得分:0)

在 Spring Boot 2 中, 您可以使用 hasRole() 或 hasAuthority()。不同之处在于,您必须为 hasAusthority() 方法使用 ROLE_。所以对于 ROLE_ADMIN,

 @PreAuthorize("hasRole('ADMIN')") == @PreAuthorize("hasAuthority('ROLE_ADMIN')")

答案 9 :(得分:0)

我遇到了类似的问题,我已经解决了。

我使用以下实体

用户实体


    @Setter
    @Getter
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @Entity
    public class User implements UserDetails, CredentialsContainer {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column(nullable = false,unique = true)
        private String username;
    
        @Column(nullable = false,unique = true)
        private String email;
    
        private String password;
    
        @Builder.Default
        private Boolean accountNonExpired = true;
    
        @Builder.Default
        private Boolean accountNonLocked = true;
    
        @Builder.Default
        private Boolean credentialsNonExpired = true;
    
        @Builder.Default
        private Boolean enabled = true;
    
        @CreationTimestamp
        @Column(updatable = false)
        private Timestamp createdDate;
    
        @UpdateTimestamp
        private Timestamp lastModifiedDate;
    
        @Singular
        @ManyToMany(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
        @JoinTable(
                name = "user_role",
                joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
                inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id")
        )
        private Set<Role> roles = new HashSet<>();
    
        @Override
        public void eraseCredentials() {
            this.password = null;
        }
    
        @Override
        @Transient
        public Collection<? extends GrantedAuthority> getAuthorities() {
            Set<SimpleGrantedAuthority> authorities =
                    this.roles.stream().
                    map(Role::getAuthorities).
                    flatMap(Set::stream).
                    map(authority -> new SimpleGrantedAuthority(authority.getPermission())).
                    collect(Collectors.toSet());
    
            roles.stream().map(Role::getName).map(SimpleGrantedAuthority::new).forEach(authorities::add);//WE NEED IT FOR hasRole() functionality
            return authorities;
        }
    
        @Override
        public boolean isAccountNonExpired() {
            return accountNonExpired;
        }
    
        @Override
        public boolean isAccountNonLocked() {
            return accountNonLocked;
        }
    
        @Override
        public boolean isCredentialsNonExpired() {
            return credentialsNonExpired;
        }
    
        @Override
        public boolean isEnabled() {
            return enabled;
        }
    }

角色实体

    @Setter
    @Getter
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @Entity
    public class Role  {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        private String name;
    
        @ManyToMany(mappedBy = "roles")
        private Set<User> users;
    
        @Singular
        @ManyToMany(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
        @JoinTable(
                name = "role_authority",
                joinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"),
                inverseJoinColumns = @JoinColumn(name = "authority_id", referencedColumnName = "id")
        )
        private Set<Authority> authorities = new HashSet<>();
    
    
    }

权威实体


    @Setter
    @Getter
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    @Entity
    public class Authority  {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        Long id;
    
        private String permission;
    
        @Singular
        @ManyToMany(mappedBy = "authorities")
        private Set<Role> roles = new HashSet<>();
    
    
    }

引导

        var storeItemCreate = authorityRepository.save(Authority.builder().permission("store.item.create").build());
        var storeItemRead = authorityRepository.save(Authority.builder().permission("store.item.read").build());
        var storeItemUpdate = authorityRepository.save(Authority.builder().permission("store.item.update").build());
        var storeItemDelete = authorityRepository.save(Authority.builder().permission("store.item.delete").build());



        var admin = roleRepository.save(Role.builder().
                authority(storeItemCreate).
                authority(storeItemRead).
                authority(storeItemUpdate).
                authority(storeItemDelete).
                name("ROLE_ADMIN").build());

        var customer = roleRepository.save(Role.builder().
            authority(storeItemRead).
            name("ROLE_CUSTOMER").
            build());

        userRepository.save(User.builder().
                role(admin).
                username("admin").
                password(passwordEncoder.encode("admin")).
                email("admin@admin.com").
                build()
        );


        userRepository.save(User.builder().
                role(customer).
                username("user").
                password(passwordEncoder.encode("user")).
                email("user@user.com").
                build()
        );

我工作 hasAuthority() 和 hasRole() 的原因是 getAuthorities 方法中用户实体的片段

        Set<SimpleGrantedAuthority> authorities =
                this.roles.stream().
                map(Role::getAuthorities).
                flatMap(Set::stream).
                map(authority -> new SimpleGrantedAuthority(authority.getPermission())).
                collect(Collectors.toSet());

        roles.stream().map(Role::getName).map(SimpleGrantedAuthority::new).forEach(authorities::add);//WE NEED IT FOR hasRole() functionality
        return authorities;

当您拥有名为 ROLE_NAMEOFROLE 的权限时,spring 将其视为角色 当前缀不存在时,spring 将其视为权威。

记住也有权限:“ROLE_ADMIN”

我不确定这是正确的方法!!!

答案 10 :(得分:0)

@组件 公共类 LoginSuccessHandler 扩展了 SavedRequestAwareAuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws ServletException, IOException {
        CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();

        String redirectURL = request.getContextPath();
        if (userDetails.hasRole("ROLE_ADMIN")) {
            redirectURL = "admin-dashboard";
        } else if (userDetails.hasRole("ROLE_EMPLOYEE")) {
            redirectURL = "dashboard";
        } else if (userDetails.hasRole("ROLE_TRAINEE")) {
            redirectURL = "dashboard";
        }
        response.sendRedirect(redirectURL);
    }

}