Writing in the front
You learned about the authentication process in Shiro and how to implement user authentication of your application with a custom Realm. In this article, we will learn about the authorization process in Shiro.
Summary of authorization
The authorization here refers to the permission granted to a user of a system to access protected resources, including query, modify, insert, and delete. Users without related permissions cannot access protected resources, and users with related permissions can only operate protected resources within their permissions.
The key object
Subject
A specified user, which can be a browser, APP, third-party application, etc.
Resources
Resources here include resources themselves and operations on resources. The resource itself has two attributes: resource type and resource instance. User information is a resource type, and southbound information is an instance of user information. Resource operations consist of querying, modifying, deleting, and adding resources.
Permission
Permissions are the permissions that a principal needs to manipulate a resource. Permissions themselves do not exist, but are simply an access identifier for a system’s protected resources. Without resources, there is no meaning to talk about authority.
Authorization process (Access control process)
Authorization Process Analysis
Prerequisites: The access subject has been authenticated and logged in to the system.
-
A user requests access to a protected resource
-
Check whether the user has access permission:
2.1 If yes, go to Step 3
2.2 If no, the user access is denied and the corresponding prompt is displayed
-
Users accessing Resources
Authorization model
At present, the main authorization modes for civil system mainly include resource-based access control and role-based access control
-
Role-based Access Control (RBAC)
The basic idea is that the various permissions for system operations are not directly granted to specific users, but to establish a role set between the user set and the permissions set. Each role has a set of rights. Once a user is assigned a role, the user has all operation rights of the role.
-
Resource-based Access Control (RBAC)
In role-based access control, once a user’s role is defined, its permissions are fixed. That is, two subjects with the same role have the same permissions. There is no way to change the principal’s permissions dynamically. Resource-based access control is designed to solve this problem.
Permission string
The permission string consists of a resource identifier, an operator, a resource instance identifier, and a delimiter in the following format: Resource Identifier: Operator: Resource instance identifier. It has the specified operation permission on one or more resource instances. If there are any resource instances, the resource instance identifier is represented by *. Separator: can also be changed to /, etc. Operators are generally classified into create, find, update, and delete. When all operations on a resource are available, operators can also be represented by *. If the resource identifier, operator, and instance identifier are all set to *, the user has the permission to access all resources in the system.
Some examples
- The query permission for user 01 is as follows:
user:find:01
- The query permission for users is:
user:find:*
oruser:find
- If user 01 has all permissions, the following command is used:
user:*:01
The above is just a list of permission string design method, you can in practice according to their own application characteristics to design their own permission string.
How authorization (access control) is implemented in Shiro
programmatic
Subject currentSubject = SecurityUtils.getSubject();
if (currentSubject.hasRole("admin")) {// Operation with permission
}else{
/ / without permission
}
Copy the code
Annotated (common)
@RequiresRoles("admin")
public boolean createUser(User user){
// You can execute methods only if you have permissions
}
Copy the code
tabbed
/ / in the JSP
<shiro:hasRole name="admin">
// Only with permissions
</shiro:hasRole>
Copy the code
Note: Additional integration is required when used in Thymeleaf.
Programming to realize
Let’s use the example from the previous article to illustrate the shiro licensing section. At the end of this article is an example of how to download
Role-based access control
Modify custom Realms to obtain character information
** Custom Realm objects *@authorLai handle being bingfengdev@aliyun.com
* @version 1.0
* @date 2020/10/4 11:00* /public class MySqlRealm extends AuthorizingRealm {
public MySqlRealm(a) {
// Set the credential matcher to hash
HashedCredentialsMatcher myCredentialsMatcher = new HashedCredentialsMatcher();
// Set the algorithm
myCredentialsMatcher.setHashAlgorithmName("md5");
// Hash times
myCredentialsMatcher.setHashIterations(1024);
this.setCredentialsMatcher(myCredentialsMatcher);
}
/** Authorization methods * For authorization methods, this is called every time the principal is judged to have the corresponding permission * therefore, caching should be done * caching will be covered later when integrating with SpringBoot *@authorLaifeng [email protected] *@dateThe 2020-10-04 11:01:50 *@param principalCollection
* @return org.apache.shiro.authz.AuthorizationInfo
* @throws AuthenticationException
* @version1.0 * /
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//1. Get the primary identity of the current principal, that is, the user name
String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();
//2. Query database with principal identity information to obtain principal permissions (simulation)
SimpleAuthorizationInfo authenticationInfo = null;
if ("xiangbei".equals(primaryPrincipal)){
authenticationInfo = new SimpleAuthorizationInfo();
authenticationInfo.addRole("admin");
}
return authenticationInfo;
}
/**认证
* @authorLaifeng [email protected] *@dateThe 2020-10-04 11:01:50 *@param authenticationToken
* @return org.apache.shiro.authz.AuthorizationInfo
* @throws AuthenticationException
* @version1.0 * /
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 1. Obtain the user name from the token
String principal = (String) authenticationToken.getPrincipal();
//2. Query database based on user name and encapsulate as authenticationInfo object return (mock)
if (principal == "xiangbei") {
// Four parameters are the database account, encrypted password, salt value, and realm name
AuthenticationInfo authInfo = new SimpleAuthenticationInfo("xiangbei"."ff595c47b51b4cf70fddce090f68879e",
ByteSource.Util.bytes("ee575f62-0dda-44f2-b75e-4efef795018f"),
this.getName());
return authInfo;
}
return null; }}Copy the code
test
hasRole
/** Access control test *@authorLaifeng [email protected] *@version 1.0
* @date 2020/10/5 16:48
*/
public class AuthzTest {
private CurrentSystemAuthenticator authenticator;
@Before
public void init(a) {
this.authenticator = new CurrentSystemAuthenticator();
// For authorization, only after the principal is authenticated can proceed, so you need to log in to the system first
this.authenticator.authenticate("xiangbei"."123");
}
@Test
public void testHasRole(a){
Subject subject = SecurityUtils.getSubject();
// The principal has a role to access
if (subject.hasRole("admin")){
System.out.println(subject.getPrincipal()+"With admin role"); }}}Copy the code
The output
Xiangbei certified! Xiangbei has the admin roleCopy the code
hasRoles
** Access control tests *@authorLai handle being bingfengdev@aliyun.com
* @version 1.0
* @date 2020/10/5 16:48* /public class AuthzTest {
private CurrentSystemAuthenticator authenticator;
@Before
public void init(a) {
this.authenticator = new CurrentSystemAuthenticator();
// For authorization, only after the principal is authenticated can proceed, so you need to log in to the system first
this.authenticator.authenticate("xiangbei"."123");
}
/** applies to only one of the roles */
@Test
public void testHasRoles(a){
Subject subject = SecurityUtils.getSubject();
boolean[] booleans = subject.hasRoles(Arrays.asList("admin"."user"));
for (boolean b : booleans) {
if (b) {
System.out.println(subject.getPrincipal()+"Have access rights");
break; }}}}Copy the code
The output
Xiangbei certified! Xiangbei has access rightsCopy the code
hasAllRoles
/** Access control test *@authorLaifeng [email protected] *@version 1.0
* @date 2020/10/5 16:48
*/
public class AuthzTest {
private CurrentSystemAuthenticator authenticator;
@Before
public void init(a) {
this.authenticator = new CurrentSystemAuthenticator();
// For authorization, only after the principal is authenticated can proceed, so you need to log in to the system first
this.authenticator.authenticate("xiangbei"."123");
}
/** Access */ only when all roles are available
@Test
public void testHasAllRoles(a){
Subject subject = SecurityUtils.getSubject();
boolean b = subject.hasAllRoles(Arrays.asList("admin"."user"));
if (b) {
System.out.println(subject.getPrincipal()+"Have access rights");
}else {
System.out.println(subject.getPrincipal()+"No access"); }}}Copy the code
The output
Xiangbei certified! Xiangbei does not have access rightsCopy the code
Resource-based access control
Modify a user-defined Realm to obtain resource permission information
/** Customize Realm objects *@authorLaifeng [email protected] *@version 1.0
* @date2020/10/4 11 * /
public class MySqlRealm extends AuthorizingRealm {
public MySqlRealm(a) {
// Set the credential matcher to hash
HashedCredentialsMatcher myCredentialsMatcher = new HashedCredentialsMatcher();
// Set the algorithm
myCredentialsMatcher.setHashAlgorithmName("md5");
// Hash times
myCredentialsMatcher.setHashIterations(1024);
this.setCredentialsMatcher(myCredentialsMatcher);
}
/** Authorization methods * For authorization methods, this is called every time the principal is judged to have the corresponding permission * therefore, caching should be done * caching will be covered later when integrating with SpringBoot *@authorLaifeng [email protected] *@dateThe 2020-10-04 11:01:50 *@param principalCollection
* @return org.apache.shiro.authz.AuthorizationInfo
* @throws AuthenticationException
* @version1.0 * /
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//1. Get the primary identity of the current principal, that is, the user name
String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();
//2. Query database with principal identity information to obtain principal permissions (simulation)
SimpleAuthorizationInfo authenticationInfo = null;
if ("xiangbei".equals(primaryPrincipal)){
authenticationInfo = new SimpleAuthorizationInfo();
//authenticationInfo.addRole("admin");
// Have all permissions of user
authenticationInfo.addStringPermission("user:*");
// Have the creation permission for the product
authenticationInfo.addStringPermission("product:create");
}
return authenticationInfo;
}
/**认证
* @authorLaifeng [email protected] *@dateThe 2020-10-04 11:01:50 *@param authenticationToken
* @return org.apache.shiro.authz.AuthorizationInfo
* @throws AuthenticationException
* @version1.0 * /
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 1. Obtain the user name from the token
String principal = (String) authenticationToken.getPrincipal();
//2. Query database based on user name and encapsulate as authenticationInfo object return (mock)
if (principal == "xiangbei") {
// Four parameters are the database account, encrypted password, salt value, and realm name
AuthenticationInfo authInfo = new SimpleAuthenticationInfo("xiangbei"."ff595c47b51b4cf70fddce090f68879e",
ByteSource.Util.bytes("ee575f62-0dda-44f2-b75e-4efef795018f"),
this.getName());
return authInfo;
}
return null; }}Copy the code
test
In the above Settings, user xiangbei has all permissions on user resources and creation permissions on products
isPermitted(String permission)
You can access a specific resource only when you have the permission to do so
/ * * *@authorLaifeng [email protected] *@version 1.0
* @date2020/10/5 17:23 * /
public class AuthzTest2 {
private CurrentSystemAuthenticator authenticator;
@Before
public void init(a) {
this.authenticator = new CurrentSystemAuthenticator();
// For authorization, only after the principal is authenticated can proceed, so you need to log in to the system first
this.authenticator.authenticate("xiangbei"."123");
}
@Test
public void testIsPermission(a) {
Subject subject = SecurityUtils.getSubject();
if (subject.isPermitted("user:create")){
System.out.println(subject.getPrincipal() + "With user creation permission"); }}}Copy the code
The output
Xiangbei certified! Xiangbei has the user creation permissionCopy the code
isPermitted(String… Permission) or isPermitted(List permissions)
This applies to situations where some of the permissions are required
/ * * *@authorLaifeng [email protected] *@version 1.0
* @date2020/10/5 17:23 * /
public class AuthzTest2 {
private CurrentSystemAuthenticator authenticator;
@Before
public void init(a) {
this.authenticator = new CurrentSystemAuthenticator();
// For authorization, only after the principal is authenticated can proceed, so you need to log in to the system first
this.authenticator.authenticate("xiangbei"."123");
}
@Test
public void testIsPermitted(a){
Subject subject = SecurityUtils.getSubject();
boolean[] permitted = subject.isPermitted("user:create"."user:find");
for (boolean b : permitted) {
if (b) {
System.out.println(subject.getPrincipal() +"Have access rights");
break; }}}}Copy the code
isPermittedAll
This applies if the principal is required to have all the listed resources to access
/ * * *@authorLaifeng [email protected] *@version 1.0
* @date2020/10/5 17:23 * /
public class AuthzTest2 {
private CurrentSystemAuthenticator authenticator;
@Before
public void init(a) {
this.authenticator = new CurrentSystemAuthenticator();
// For authorization, only after the principal is authenticated can proceed, so you need to log in to the system first
this.authenticator.authenticate("xiangbei"."123");
}
@Test
public void testIsPermittedAll(a) {
Subject subject = SecurityUtils.getSubject();
boolean b = subject.isPermittedAll("product:*");
if (b) {
System.out.println(subject.getPrincipal() +"Have all permissions on the Product module");
}else {
System.out.println(subject.getPrincipal() +"Do not have access to the product module"); }}Copy the code
The output
Xiangbei certified! Xiangbei does not have access to the product moduleCopy the code
Write in the back
In this article, we mainly studied shrio access control, and through a simple example to demonstrate. In the next Shiro series, the authors will cover SpringBoot’s integration with Shiro.
If you find this article helpful, please give it a thumbs up. If there is any mistake, please feel free to comment. Here, thank you folks!
Download method of this article example: wechat search “Java development Practice”, reply 20201005 to get the download link.