Shiro authentication strategy-shiro customize Realm to achieve authentication-shiro hash encryption algorithm-shiro authorization-shiro customize Realm to achieve authorization

Shiro verification strategy

Authentication Strategy: authentication strategy, there are three authentication strategies in shiro;

AtleastOneSuccessfulStrategy [default]

If one or more Realm verifications are successful, the overall attempt is considered successful. If none of the verification succeeds, the overall attempt fails;

FirstSuccessfulStrategy

Only the information returned by the first successfully verified Realm will be used. All further Realm will be ignored. If none of the verification succeeds, the overall attempt fails.

AllSuccessfulStrategy

In order for the overall attempt to succeed, all configured Realms must be verified successfully. If none of the verification succeeds, the overall attempt fails

authenticationStrategy=org.apache.shrio.authc.pam.FirstSuccessfulStrategy

securityManager.authentication.authenticationStrategy=$authenticationStrategy

[main]

dataSource = com.mchange.v2.c3p0.ComboPooledDataSource

dataSource.driverClass=com.mysql.jdbc.Driver

dataSource.jdbcUrl=jdbc:mysql://localhost:3306/myshiro

dataSource.user=root

dataSource.password=1234567

jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm

#$ means reference object

jdbcRealm.dataSource=$dataSource

#Configure validator

authenticationStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy

securityManager.realm=$jdbcRealm

securityManager.authenticator.authenticationStrategy=$authenticationStrategy

Customize realm to achieve identity authentication

JdbcRealm has achieved user authentication information from the database, but the flexibility of jdbcRealm is too poor. If you want to implement some of your own special applications, it will not be supported. At this time, we can implement the identity authentication function by customizing the realm.

   Realm is an interface in which the method for obtaining authentication information based on the token is defined. Shiro content implements a series of realms. These different Realm implementation classes provide different functions. AuthenticatingRealm implements the function of obtaining identity information, and AuthoringRealm implements the function of authority information. Usually custom Realm needs to inherit AuthoringRealm, which can provide both freely defined methods of identity authentication and custom methods of authorization .

public class UserRealm extends AuthorizingRealm{

 

    @Override

    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection token) {

       // TODO Auto-generated method stub

       String username = (String)token.getPrimaryPrincipal();

       String pwd = "1111";//相当于从数据库中取得

       SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,pwd,getName());

       return (AuthorizationInfo) info;

    }

 

    @Override

    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {

       // TODO Auto-generated method stub

       return null;

    }

   

}

Shiro.ini

[main]

userRealm=com.pshdhx.UserRealm

securityManager.realm=$userRealm

注意:使用shiro来完成权限管理,shiro并不会去维护数据。Shiro中使用的数据,需要程序员根据处理业务将数据传递给给shiro的相关接口;

散列算法(加密)

1、在身份认证过程中往往会涉及加密。如果不加密那么数据信息不安全。Shiro内容实现了比较多的散列算法。如MD5加密,SHA等。并且提供了加盐功能。比如1111的md5加密是确定的“b59c67bf196a4758191e42f76670ceba”==直接在navicat中查询select MD5('1111')即可得到。这个md5加密很容易被破解,但是如果1111+姓名,那么找到原密码的难度会增加。

package com.pshdhx;

 

import org.apache.shiro.crypto.hash.Md5Hash;

 

public class MD5Demo {

    public static void main(String[] args) {

       //普通md5加密1111

       Md5Hash md5 = new Md5Hash("1111");

       System.out.println(md5.toString());

       //盐加密

       md5 = new Md5Hash("1111", "com.pshdhx");

       System.out.println(md5.toString());

       //盐加密+迭代次数

       md5 = new Md5Hash("1111", "com.pshdhx", 2);

       System.out.println(md5.toString());

    }

}

b59c67bf196a4758191e42f76670ceba

799367c240adf5478aa2c2a1c081b0bd

458563a4756175ca15176053ca82711c

 

 

 

授权

授权:给通过身份认证的人,授予他可以访问某些资源的权限;

权限粒度:粗粒度:对表的curd;细粒度:是对记录的操作。如只允许查看id为1的一条记录。Shiro一般管理的是粗粒度的权限。比如:菜单,按钮,url。一般细粒度的权限是通过业务来控制的。

角色:权限的集合。管理授权方便。

权限表示规则:资源:操作:实例。可以用通配符表示:

  如user:add  表示对user有添加的权限

User:*  表示对user有所有的权限;

User:delete:100  表示对user标识为100的实例具有删除的权限;

 

package com.pshdhx;

 

import java.util.Arrays;

 

import org.apache.shiro.SecurityUtils;

import org.apache.shiro.authc.AuthenticationException;

import org.apache.shiro.authc.UsernamePasswordToken;

import org.apache.shiro.authz.AuthorizationException;

import org.apache.shiro.config.IniSecurityManagerFactory;

import org.apache.shiro.mgt.SecurityManager;

import org.apache.shiro.subject.Subject;

import org.apache.shiro.util.Factory;

 

public class AuthorizationDemo {

    public static void main(String[] args) throws Exception {

       Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");

       SecurityManager securityManager = factory.getInstance();

       SecurityUtils.setSecurityManager(securityManager);

       Subject subject = SecurityUtils.getSubject();

       UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "1111");

       try {

           subject.login(token);

       } catch (AuthenticationException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

           System.out.println("认证不通过");

       }

      

       boolean hasRole = subject.hasRole("role1");

      

       System.out.println("role1的存在==="+hasRole);

      

       try {

           subject.checkRole("role1");  //该角色不存在则抛出Un authorized Exception

       } catch (AuthorizationException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

           System.out.println("角色不存在");

       }

       //判断有多少个角色

       boolean[] hasRoles = subject.hasRoles(Arrays.asList("role1","role2"));

       //subject.checkRoles("role1","role2");

      

       //基于资源的授权

       boolean userAdd = subject.isPermitted("user:add");

       System.out.println("subject:zhangsan具有userAdd的权限吗"+userAdd);

       //判断具有多个授权

       subject.isPermittedAll("user:add","user:delete");   

    }

}

 

[users]

zhangsan=1111,role1

lisi=1111,role2

[roles]

role1=user:add,user:update,user:delete

role2=user:*

Shiro的权限检查方式

方式1:编程式

方式2:注解式

方式3::标签式

If(subject.hasRole(“admin”))

@RequiresRoles(“admin”):在执行指定的方法时会检查是否具有该权限,不需要了url的拦截 

Public void list()

 

 

 

授权流程:

  获取subject的主体

  判断主体是否通过认证

  调用subject.isPermitted()/hasRole()的方法来进行权限的判断

Subject是由其实现类DelegatingSubject来调用方法的,该类将处理交给了SecurityManager;

SecurityManager是由其实现类DefaultSecurityManager的isPermitted的方法

来处理,本质是交给其父类-AuthorazitionSecurityManager来处理的。该类将处理处理交给了authorzer()授权器来处理的

Authrozer()由其实现类ModularRealmAuthorzer来处理。该类可以调用调用对应的Realm来获取数据,在该类有PermissionResolver对权限字符串进行解析,在对应的Realm中也有对应的PermissionResolver交给WildcardPermissionResolver该类调用WildcardPermission来进行权限字符串的解析。然后返回处理结果。

 

自定义Realm实现授权

通过配置文件指定权限不够灵活,并且不方便。在实际应用中大多数情况下都是将用户信息,角色信息保存到数据库中。所以需要从数据库中获取相关的数据信息。可以使用Shiro提供的jdbcRealm来实现,可以自定义Realm来实现。使用JDBCRealm往往也不够灵活,所以在实际应用中大多数情况下都是自定义Realm来实现。

自定义Realm需要继承AuthorazingRealm,重写方法

package com.pshdhx;

 

import java.util.ArrayList;

import java.util.List;

 

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;

/**

 * 自定义Realm的实现,该Realm类提供了两个方法

 * doGetAuthorizationInfo 获取认证信息

 * doGetAuthenticationInfo 获取权限信息

 */

public class UserRealm extends AuthorizingRealm{

   

    @Override

    public String getName(){

       return "userRealm";

    }

   

    //身份认证

    @Override

    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

       // TODO Auto-generated method stub

              String username = (String)token.getPrincipal();  //获取身份信息

              System.out.println("username===="+username);

              String pwd = "1111";//相当于从数据库中取得

              //pwd="b59c67bf196a4758191e42f76670ceba";

              //String salt = "pshdhx";

              //将数据库中查询到的信息封装到SimpleAuthenticationInfo

              SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,pwd,getName());

              return info;

    }

   

    //授权的信息

    @Override

    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {

       // TODO Auto-generated method stub

       String username  = (String)principal.getPrimaryPrincipal();

       //根据用户名去数据库中查询该用户对应的权限的

       List<String> permission  = new ArrayList<>();

       permission.add("user:add");

       permission.add("user:delete");

       permission.add("user:find");

       permission.add("user:update");

       SimpleAuthorizationInfo  info = new SimpleAuthorizationInfo();

       for(String perms : permission){

           info.addStringPermission(perms);

       }

       return info;

    }

   

   

   

}

 

[main]

userRealm=com.pshdhx.UserRealm

securityManager.realm=$userRealm

[users]

zhangsan=1111

lisi=1111

package com.pshdhx;

 

import java.lang.reflect.Array;

 

import org.apache.shiro.SecurityUtils;

import org.apache.shiro.authc.AuthenticationException;

import org.apache.shiro.authc.UsernamePasswordToken;

import org.apache.shiro.config.IniSecurityManagerFactory;

import org.apache.shiro.mgt.SecurityManager;

import org.apache.shiro.subject.Subject;

import org.apache.shiro.util.Factory;

public class UserRealmDemo {

    public static void main(String[] args) {

       Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");

       SecurityManager securityManager = factory.getInstance();

       SecurityUtils.setSecurityManager(securityManager);

       Subject subject = SecurityUtils.getSubject();

       UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "1111");

       try {

           subject.login(token);

           if(subject.isAuthenticated()){

              System.out.println("验证通过");

           }

       } catch (AuthenticationException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

           System.out.println("验证不通过");

       }

       boolean[] permitted = subject.isPermitted("user:add","user:delete");

       System.out.println(permitted[1]+"=="+permitted[0]);

    }

}

验证通过

true==true

Guess you like

Origin blog.csdn.net/pshdhx/article/details/107902278