3

My application needs me to define multiple roles for a single user .

I have read Spring security with database and multiple roles? .

Why should we implement our own UserDetails ? Existing one contains

Collection getAuthorities();

Also is there any reference or tutorial which I can follow for implementing multiple roles for a single user ?

Community
  • 1
  • 1
Vinoth Kumar C M
  • 10,378
  • 28
  • 89
  • 130

3 Answers3

2

In case anybody is interested in a custom UserDetailsService for comma-separated authorities:

@Component
public class MyUserDetailsService implements UserDetailsService {

    @Resource
    private AccountService accounts;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        Account account = accounts.findByUsername(username);
        if(null == account) {
            throw new UsernameNotFoundException("User " + username + " not found.");
        }

        List<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
        String[] authStrings = account.getAuthorities().split(", ");
        for(String authString : authStrings) {
            authorities.add(new SimpleGrantedAuthority(authString));
        }

        UserDetails ud = new User(account.getUsername(), account.getPassword(), authorities);
        return ud;
    }

}

Now you can have something like this in the db:

+----+-----------------------+----------+----------+
| id | authorities           | password | username |
+----+-----------------------+----------+----------+
|  1 | ROLE_ADMIN            | 123qwe   | markm    |
|  2 | ROLE_ADMIN, ROLE_USER | 123qwe   | kemika   |
+----+-----------------------+----------+----------+
markbaldy
  • 2,521
  • 1
  • 14
  • 10
2

The accepted answer to the post you have referenced doesn't seem correct to me. You don't have to create your own UserDetailsService implementation for this. Multiple roles are already supported. See JdbcDaoImpl. You have to just make sure that authoritiesByUsernameQuery matches with your database set up. By default its value is select username,authority from authorities where username = ?. This query is executed by loadUserAuthorities method that loads all authorities.

Ritesh
  • 7,472
  • 2
  • 39
  • 43
  • I tried this and instead of splitting ROLE_ADMIN,ROLE_USER into 2 roles, I got the whole string as a single role "ROLE_ADMIN,ROLE_USER" which needless to say does not work – markbaldy Jun 05 '13 at 06:56
  • @markbaldy I am not sure if I got the issue. Can you add code to show what you have tried? – Ritesh Jun 06 '13 at 06:47
  • Using your solution the whole string was returned as a single permission: "ROLE_ADMIN,ROLE_USER", instead of ["ROLE_ADMIN","ROLE_USER"]. I did need to implement my own UserDetailsService. – markbaldy Jun 07 '13 at 07:04
  • I guess I am trying to understand where do you get that string. The loadUserAuthorities method of JdbcDaoImpl returns a list of GrantedAuthority. – Ritesh Jun 07 '13 at 15:34
0

Spring security supports more-than-one roles out-of-the-box!

So, to save all of you fine folks a ton of time:

One must insert multiple entries for the same user: enter image description here That was in MySQL Workbench, with MySQL 5.7.24 Also other environments - in case you wondering which version to reproduce that result:

    <!-- Inherit defaults from Spring Boot -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
    </parent>
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!-- optional, it brings useful tags to display spring security stuff -->
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        </dependency>

Then to verify I made this page and: enter image description here

Here's the example code for displaying and verifying the logged in account's authorities:

<div data-layout-fragment="content" class="content">
    <div class="row mt-4">
    <div class="col-md-12">
        <h2>Show Authorities Glance</h2>
        <div class="card">
        <div class="card-body">
            Logged user: <span data-sec-authentication="name">Bob</span>
            Roles: <span data-sec-authentication="principal.authorities">[ROLE_USER, ROLE_ADMIN]</span>
            <div data-sec-authorize="isAuthenticated()">
            This content is only shown to authenticated users.
            </div>
            <div data-sec-authorize="hasRole('ROLE_USER')">
            This content is only shown to ROLE_USER.
            </div>
            <div data-sec-authorize="hasRole('ROLE_EMPLOYEE')">
            This content is only shown to ROLE_EMPLOYEE.
            </div>
            <div data-sec-authorize="hasRole('ROLE_FOUNDER')">
            This content is only shown to ROLE_FOUNDER.
            </div>
            <div data-sec-authorize="hasRole('ROLE_ADMIN')">
            This content is only shown to ROLE_ADMIN.
            </div>
        </div>
        </div>
    </div>
    </div>
</div>
<!--<p>-->
    <!--<a data-th-href="@{/add-authority}">Add a new authority</a>-->
<!--</p>-->
</div>

Oh and this last view contains thymeleaf and not only the standard one also the layout dialect. Just in case you would like to try it out also need this dependency:

<dependency>
    <groupId>nz.net.ultraq.thymeleaf</groupId>
    <artifactId>thymeleaf-layout-dialect</artifactId>
</dependency>

Or get ride of the layout fragment tag:

data-layout-fragment="content"
marsrover
  • 424
  • 5
  • 16