Permissions (and widely understood security) is one of the most important part of majority of modern applications. Over the years software developers have come up with many different ways of handling privileges in their projects. I’m guessing that in the present day the most popular way of tackling data access is using database but, for the sake of this blog post, let’s assume that we do not employ any relational database system.

So, how to handle them? 🙂

Binary (bit) flags

Bitwise operators are commonly used for working with set of flags and bitmasks. Thanks to this, permission flags can be represented by individual bits. It’s efficient when it comes to storage and code. At first it may appear too complicated, but the initial confusion will be cleared up with time.

We’re going to start with defining some basic permissions:

enum class Permission(val flag: Int) { READ(0b000001), WRITE(0b000010), DELETE(0b000100), READ_PERMISSIONS(0b001000), WRITE_PERMISSIONS(0b010000), DELETE_PERMISSIONS(0b100000); }

The permission bit each bitmask is representing, is set to 1, others to 0. We can also store the bitmasks in the decimal numeral system, like this: READ(1), WRITE(2), WRITE_PERMISSIONS(16) but I think it’s more confusing.

Now, if we want to check if user has READ permission, we can use bitwise AND operation:

fun canRead(userPermissionFlags: Int): Boolean { return userPermissionFlags and Permission.READ.flag != 0 }

Here the bitwise AND operation is used to determine whether a particular bit is set. If it’s set, then the operation returns 1, otherwise it’s 0 (and that’s why we compare the whole expression to 0).

In order to combine the bit flags, we need to use the OR operation. The result of this operation is 1, if any of the corresponding bits is equal 1 – and if not, the result is 0. Let’s give John and Adam few different privileges and confront them with the previously created method:

val johnsPermissions = Permission.READ.flag or Permission.WRITE.flag val adamsPermissions = Permission.DELETE.flag or Permission.READ_PERMISSIONS.flag if (canRead(johnsPermissions)) { println("John can read a book") } if (canRead(adamsPermissions)) { println("Adam can read a book") }

In the first case, the message will be printed to the output log, the second condition body won’t be executed.

And that’s it!

You can combine the bits however you want. You can group them into permission groups, you can create another entry in the enum class to easily distinguish administrators. Whatever you imagine.

At the beginning of this post I mentioned that we’re not going to use any database system for handling permissions – and that’s true, we didn’t, but remember that storing just additional column with an integer representing permissions is really efficient.

I hope that I’ve managed to clear up your confusion about handling permissions in a bit way. Here’s a little extra snippet from me, in case you want to get the permission flag in human readable form:

fun getPermissions(permissionFlags: Int): Set<Permission> { val permissions = mutableSetOf<Permission>() for (permission in Permission.values()) { val flagValue = permission.flag if (flagValue and permissionFlags == flagValue) { permissions.add(permission) } } return permissions }

The whole example is available on my GitHub profile. Feel free to play around.