catalogue
1, Basic concept of permission
1. What is permission management
2. What is identity authentication
3, Shrio first program user authentication
(2) Principal: identity information
(3) Credential: credential information
(2) Introducing shiro dependency
4. Interpretation of authentication source code
5. Instance Optimization: Custom Realm
5, Authentication in Shiro: implementation of MD5+Salt+Hash
1. Query the ciphertext corresponding to the password
2. Implementation of MD5+Salt+Hash in Shiro
4. Programming implementation of authorization
1, Basic concept of permission
1. What is permission management
Permission management belongs to the category of system security. Permission management realizes the control of users' access to the system and controls that users can and can only access their authorized resources according to security rules.
Authority management includes identity authentication and authorization.
2. What is identity authentication
The process of judging whether a user is a legal user.
The most common methods are user name and password, fingerprints, face brushing and so on.
3. What is authorization
Authorization, or access control, controls who can access which resources.
2, Basic knowledge of Shiro
1. What is Shiro
Official website address: http://shiro.apache.org/
Shiro is an open source framework under Apache. It extracts the functions related to security authentication of software system, realizes user identity authentication, authority authorization, encryption, session management and other functions, and forms a general security authentication framework.
2. Core architecture of Shiro
3, Shrio first program user authentication
1. Basic concepts
(1) Subject: subject
Users accessing the system are authenticated by the main body
(2) Principal: identity information
It is the identification of the subject for identity authentication and has uniqueness. A subject can have multiple identities, but it must have one primary identity
(3) Credential: credential information
Only the subject knows the security information
2. Certification process
The subject generates additional information through identity information and voucher information, and then verifies whether the token is legal.
3. Example preparation
(1) Create project
After creation, maven will be automatically introduced, and then two new resources folders will be added:
(2) Introducing shiro dependency
(3) Import shiro profile
Note that shiro is a configuration file ending in ini, not a regular property or yml.
The configuration file only needs to be placed in any directory under resources.
We don't notice that ini is used to write the relevant files in this project. It eliminates the operation related to editing the database and simplifies the learning process
The above [users] is fixed:
(4) Write control class
package com.xupeng; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.realm.text.IniRealm; import org.apache.shiro.subject.Subject; public class TestAuthenticator { public static void main(String[] args) { //1. Create security manager object DefaultSecurityManager securityManager = new DefaultSecurityManager(); //2. Set realm to the Security Manager (realm provides relevant data) securityManager.setRealm(new IniRealm("classpath:shiro.ini")); //3.SecurityUtils global security tool class SecurityUtils.setSecurityManager(securityManager); //4. Key object: subject object Subject subject = SecurityUtils.getSubject(); //5. Create token UsernamePasswordToken token = new UsernamePasswordToken("xupeng","456"); try{ System.out.println("Certification status:"+subject.isAuthenticated()); subject.login(token);//User login authentication System.out.println("Certification status:"+subject.isAuthenticated()); }catch (UnknownAccountException e){ e.printStackTrace(); System.out.println("Authentication failed. The authenticated user does not exist"); }catch (IncorrectCredentialsException e){ e.printStackTrace(); System.out.println("Authentication failed, password error"); } } }
(5) Testing
We will find that the status has changed, which proves that the login is successful
4. Interpretation of authentication source code
(1) The authentication of the final user name is in SimpleAccountRealm:
(2) The verification of password is in the AuthenticatingRealm class:
Once our password is incorrect, it will report an IncorrectCredentialsException exception, and the source code will be clear here
5. Instance Optimization: Custom Realm
In the above example, the user name and password are written in the ini file, but in actual use, they must be placed in the database. Let's simulate the database and make a simple example first
CustomerRealm:
package com.xupeng.realm; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; /** * Customize the implementation of Realm to convert the source of authentication / authorization data into the implementation of database */ public class CustomerRealm extends AuthorizingRealm { //to grant authorization @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { return null; } //authentication @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //Get user name in token String principal = (String) authenticationToken.getPrincipal(); System.out.println(principal); //Use jdbc mybatis to query relevant databases according to identity information if("xupeng".equals(principal)){ //Parameter 1: correct user name in database //Parameter 2: correct password in database //Parameter 3: provide current Realm name SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo("xupeng","456",this.getName()); return simpleAuthenticationInfo; } return null; } }
TestCustomerRealmAuthenticator:
package com.xupeng; import com.xupeng.realm.CustomerRealm; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.subject.Subject; /** * Use custom Realm */ public class TestCustomerRealmAuthenticator { public static void main(String[] args) { //Create SecurityManager DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); //Set custom realm defaultSecurityManager.setRealm(new CustomerRealm()); //Set security tool class SecurityUtils.setSecurityManager(defaultSecurityManager); //Obtain the subject through the security tool class Subject subject = SecurityUtils.getSubject(); //Create token UsernamePasswordToken token = new UsernamePasswordToken("xupeng","456"); try { subject.login(token); System.out.println(subject.isAuthenticated()); }catch (UnknownAccountException e){ e.printStackTrace(); System.out.println("Authentication failed. The authenticated user does not exist"); }catch (IncorrectCredentialsException e){ e.printStackTrace(); System.out.println("Authentication failed, password error"); } } }
Test:
4, DM5 and Salt
The database cannot store passwords in clear text. We need MD5 encryption and Salt.
1.MD5 algorithm
(1) Characteristics
- MD5 algorithm is irreversible.
- If the contents are the same, the results generated by md5 will be the same no matter how many times it is executed
(2) Function
Generally used for encryption or signature.
Signature let's explain here. When we download software, we often see an md5 suffix file on the official website, which is used to verify whether the software you download is missing. After md5 encryption, the downloaded file should be the same as the file with md5 suffix provided on the official website.
(3) Generate results
The result generated by md5 is always a hexadecimal 32-bit string
2.Salt
(1) MD5 algorithm problem
Now there are exhaustive websites on the Internet. If we directly save MD5 with our password, it's easier to compare with exhaustive websites with MD5. So we add some of our own things to the password, which is called salt. Increase the complexity of comparison and ensure the relative security of passwords.
3.md5+salt+hash hash instance
5, Authentication in Shiro: implementation of MD5+Salt+Hash
1. Query the ciphertext corresponding to the password
TestShiroMD5
package com.xupeng; import org.apache.shiro.crypto.hash.Md5Hash; public class TestShiroMD5 { public static void main(String[] args) { //Direct use of md5 algorithm Md5Hash md5Hash = new Md5Hash("456"); System.out.println(md5Hash.toHex()); //Using md5+salt Md5Hash md5Hash1 = new Md5Hash("456","xp"); System.out.println(md5Hash1.toHex()); //Use md5+salt+hash hash //Where 1024 indicates 1024 hashes of salt addition results Md5Hash md5Hash2 = new Md5Hash("456","xp",1024); System.out.println(md5Hash2.toHex()); } }
2. Implementation of MD5+Salt+Hash in Shiro
CustomerMd5Realm:
package com.xupeng.realm; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.ByteSource; /** * Customize the implementation of Realm and add md5+salt+hash hash */ public class CustomerMd5Realm extends AuthorizingRealm { //to grant authorization @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { return null; } //authentication @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //Get user name in token String principal = (String) authenticationToken.getPrincipal(); System.out.println(principal); //Use jdbc mybatis to query relevant databases according to identity information if("xupeng".equals(principal)){ //Parameter 1: correct user name in database //Parameter 2: correct MD5 password in database //Parameter 3: provide current Realm name // SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo( // "xupeng", // "250cf8b51c773f3f8dc8b4be867a9a02", // this.getName()); //Parameter 1: correct user name in database //Parameter 2: correct MD5 password + salt password in the database. If the number of hashes is added, the password after hashing is set //Parameter 3: random salt at registration //Parameter 4: provide current Realm name SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo( "xupeng", "4ca532fb479910d125d72992a3f57b33", ByteSource.Util.bytes("xp"), this.getName()); return simpleAuthenticationInfo; } return null; } }
TestCustomerMd5RealmAuthenticator:
package com.xupeng; import com.xupeng.realm.CustomerMd5Realm; import com.xupeng.realm.CustomerRealm; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.subject.Subject; /** * Use custom Realm and add md5+salt+hash hash */ public class TestCustomerMd5RealmAuthenticator { public static void main(String[] args) { //Create SecurityManager DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); //Inject Realm CustomerMd5Realm customerMd5Realm = new CustomerMd5Realm(); //Set realm to use hash credential matcher HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); credentialsMatcher.setHashAlgorithmName("md5"); credentialsMatcher.setHashIterations(1024); customerMd5Realm.setCredentialsMatcher(credentialsMatcher); defaultSecurityManager.setRealm(customerMd5Realm); //Set security tool class SecurityUtils.setSecurityManager(defaultSecurityManager); //Obtain the subject through the security tool class Subject subject = SecurityUtils.getSubject(); //Create token UsernamePasswordToken token = new UsernamePasswordToken("xupeng","456"); try { subject.login(token); System.out.println(subject.isAuthenticated()); }catch (UnknownAccountException e){ e.printStackTrace(); System.out.println("Authentication failed. The authenticated user does not exist"); }catch (IncorrectCredentialsException e){ e.printStackTrace(); System.out.println("Authentication failed, password error"); } } }
6, Authorization in Shiro
Authorization, or access control, controls who can access which resources.
1. Basic concepts
(1) Host: Subject
(2) Resource: Resource
(3) Permission: permission
2. Authorization method
- Role based access control
- Resource based access control
3. Permission string
For resource-based access control, the rule of permission string is:
Resource identifier: Action: resource instance identifier
It means what operations are performed on which instance of that resource
example:
User creation permission:
user:create, or user:create:*
User's permission to modify instance 001:
user:update:001
All permissions of user instance 001:
user:*:001
4. Programming implementation of authorization
(1) Programming
(2) Annotation type
(3) Label type
5. Authorized instance code
The premise of authorization is to pass the authentication. Let's take the example of MD5 + salt + hash above to operate:
CustomerMd5Realm:
The doGetAuthorizationInfo method is used for authorization
package com.xupeng.realm; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.ByteSource; /** * Customize the implementation of Realm and add md5+salt+hash hash */ public class CustomerMd5Realm extends AuthorizingRealm { //to grant authorization @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("------------------------"); String principal = (String) principalCollection.getPrimaryPrincipal(); System.out.println("Identity information:"+principal); //Obtain the role information and permission information of the current user according to the identity information and user name SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); simpleAuthorizationInfo.addRole("admin"); simpleAuthorizationInfo.addRole("user"); //Copy the query permission information in the database to the permission object simpleAuthorizationInfo.addStringPermission("user:*:01"); simpleAuthorizationInfo.addStringPermission("product:create"); return simpleAuthorizationInfo; } //authentication @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //Get user name in token String principal = (String) authenticationToken.getPrincipal(); System.out.println(principal); //Use jdbc mybatis to query relevant databases according to identity information if("xupeng".equals(principal)){ //Parameter 1: correct user name in database //Parameter 2: correct MD5 password in database //Parameter 3: provide current Realm name // SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo( // "xupeng", // "250cf8b51c773f3f8dc8b4be867a9a02", // this.getName()); //Parameter 1: correct user name in database //Parameter 2: correct MD5 password + salt password in the database. If the number of hashes is added, the password after hashing is set //Parameter 3: random salt at registration //Parameter 4: provide current Realm name SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo( "xupeng", "4ca532fb479910d125d72992a3f57b33", ByteSource.Util.bytes("xp"), this.getName()); return simpleAuthenticationInfo; } return null; } }
TestCustomerMd5RealmAuthenticator
package com.xupeng; import com.xupeng.realm.CustomerMd5Realm; import com.xupeng.realm.CustomerRealm; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.subject.Subject; import java.util.Arrays; /** * Use custom Realm and add md5+salt+hash hash */ public class TestCustomerMd5RealmAuthenticator { public static void main(String[] args) { //Create SecurityManager DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); //Inject Realm CustomerMd5Realm customerMd5Realm = new CustomerMd5Realm(); //Set realm to use hash credential matcher HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); credentialsMatcher.setHashAlgorithmName("md5"); credentialsMatcher.setHashIterations(1024); customerMd5Realm.setCredentialsMatcher(credentialsMatcher); defaultSecurityManager.setRealm(customerMd5Realm); //Set security tool class SecurityUtils.setSecurityManager(defaultSecurityManager); //Obtain the subject through the security tool class Subject subject = SecurityUtils.getSubject(); //Create token UsernamePasswordToken token = new UsernamePasswordToken("xupeng","456"); try { subject.login(token); System.out.println(subject.isAuthenticated()); }catch (UnknownAccountException e){ e.printStackTrace(); System.out.println("Authentication failed. The authenticated user does not exist"); }catch (IncorrectCredentialsException e){ e.printStackTrace(); System.out.println("Authentication failed, password error"); } //Authenticate users for authorization if(subject.isAuthenticated()){ //1. Role based permission control System.out.println(subject.hasRole("admin")); //2. Multi role based permission control System.out.println(subject.hasRoles(Arrays.asList("admin","user"))); //3. Do you have one of these roles boolean[] booleans = subject.hasRoles(Arrays.asList("admin","super","user")); for(boolean b:booleans){ System.out.println(b); } System.out.println("================================"); //Access control resource identifier based on permission string: Action: resource instance identifier System.out.println("resources:"+subject.isPermitted("user:update:01")); System.out.println("resources:"+subject.isPermitted("product:create:02")); //What permissions do you have boolean[] permitted = subject.isPermitted("user:*:01","order:*:10"); for(boolean b:permitted){ System.out.println(b); } //What permissions do you have at the same time boolean permitAll = subject.isPermittedAll("user:*:01","product:create"); System.out.println(permitAll); } } }
7, Reward request
If this blog is helpful to you, please give me a reward. Thank you~