shiro快速入门案例

Apache Shiro是什么?

  • Apache Shiro是一个强大且易用的Java安全框架,可执行身份验证(登录)、授权、密码学和会话管理

架构图

组件基本说明:

  • subject(主体):接收客户端账号密码,有一系列的认证授权方法
  • security manager(安全管理器):管理所有的subject,并使用底层组件完成操作
  • authenticator(认证/登录校验):对subject的身份进行认证,最简单可以理解为对用户的账号密码进行校验
  • authorize(授权):subject认证通过后,在访问功能时需要通过授权器判断用户是否有此功能的操作权限
  • realm(域):对当前subject的权限管理数据进行封装(从数据库中获取),分别有认证和授权两个
  • session manager(会话管理器):类似于web session域的session管理域
  • sessionDAO(会话DAO):shiro session的Dao类
  • cache manager(缓存管理器):用于缓存权限信息,提高系统性能
  • crypography(密码学):一套加密api

快速入门案例

数据库表:
user

user_role

role_permission

maven依赖:

<!-- shiro-core -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.3.2</version>
</dependency>


<!-- 数据库驱动:mysql -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.38</version>
</dependency>


<!-- 连接池:druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.6</version>
</dependency>

** 数据库工具类:**

public class DBUtil {

    private DBUtil() {}
    
    private static DruidDataSource druidDataSource = null;
    
    static {
        druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("root");
    }
    
    public static DruidPooledConnection getConnection() throws SQLException {
        return druidDataSource.getConnection();
    }
    
    public static DataSource getDataSource() {
        return druidDataSource;
    }
    
}

** 需要认证授权的用户信息(模拟表填提交的数据):**

public enum Users {
    ADMIN("admin", "123456"), TEST("test", "123456");
    
    private String username;
    private String password;
    Users(String username, String password) {
        this.username = username;
        this.password = password;
    }
    
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    
}

** 入门案例: **

/**
 * 使用shiro提供的SimpleAccountRealm进行认证(不支持自定义授权)
 */
public class SimpleAccountRealmTest {
    
    //备用。用于存放查询出来的角色名称
    private static String[] userRoles = new String[5]; 
    
    //创建一个shiro提供的简单Realm,不支持自定义授权
    private static SimpleAccountRealm realm = new SimpleAccountRealm();
    
    //初始化realm信息
    static {
        
        try {
            
            DruidPooledConnection connection = DBUtil.getConnection();
            
            //获取需要认证用户的user信息
            PreparedStatement userPrepareStatement = connection.prepareStatement("select * from user where username=?"); 
            userPrepareStatement.setString(1, Users.ADMIN.getUsername());
            ResultSet userRs = userPrepareStatement.executeQuery();
            userRs.next(); //username唯一所以只有一个rs
            
            //根据用户信息(username)查找出对应的role
            PreparedStatement rolePrepareStatement = connection.prepareStatement("select * from user_role where username=?");
            rolePrepareStatement.setString(1, Users.ADMIN.getUsername());
            ResultSet roleRs = rolePrepareStatement.executeQuery();
            
            int i = 0;
            while(roleRs.next()) { //可能有多个角色
                userRoles[i++] = roleRs.getString("role_name");
            }
            
            
            /**
             * 注意:这里的account信息应该是数据库中的信息
             */
            realm.addAccount(userRs.getString("username"), userRs.getString("password"), userRoles); //将该账号信息设置到realm中
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
    
    public static void main(String[] args) {
    
        // 1. 获取默认的SecurityManager
        DefaultSecurityManager sm = new DefaultSecurityManager();
        sm.setRealm(realm);
        
        // 2. 设置到工具中
        SecurityUtils.setSecurityManager(sm);
        
        // 3. 获取主体
        Subject subject = SecurityUtils.getSubject();
        
        // 4. 创建token
        UsernamePasswordToken token = new UsernamePasswordToken(Users.ADMIN.getUsername(), Users.ADMIN.getPassword());
        
        // 5. 认证
        subject.login(token);
        
        System.out.println( "是否认证成功: " + subject.isAuthenticated() );
        System.out.println( "是否有super这个角色: " +  subject.hasRole("super"));
        System.out.println( "是否有default这个角色: " +  subject.hasRole("default"));
//      boolean[] hasRoles = subject.hasRoles(Arrays.asList(userRoles)); //是否同时有super和default这个角色
        
        
    }

}

shiro提供的realm基本使用

** IniRealm: **
auth.ini:

[users]
admin=123456,super,default
test=123456,default

[roles]
super=user:delete,user:select,user:update,user:insert
default=user:select

code:

/**
 * 使用shiro提供的IniRealm进行认证(使用配置文件保存认证授权信息)
 */
public class IniRealmTest {
    
    private static IniRealm iniRealm;
    
    static {
        iniRealm = new IniRealm("classpath:auth.ini");
    }

    public static void main(String[] args) {

        

        // 1. 获取默认的SecurityManager
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(iniRealm);

        // 2. 设置到工具中
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        
        // 3. 获取主体
        Subject subject = SecurityUtils.getSubject();

        // 4. 创建token
        UsernamePasswordToken token = new UsernamePasswordToken(Users.ADMIN.getUsername(), Users.ADMIN.getPassword());
//        UsernamePasswordToken token = new UsernamePasswordToken(Users.TEST.getUsername(), Users.TEST.getPassword());
//        UsernamePasswordToken token = new UsernamePasswordToken("AAAA", "XXX"); //UnknownAccountException 没有该账号
//        UsernamePasswordToken token = new UsernamePasswordToken(Users.TEST.getUsername(), "XXX"); //IncorrectCredentialsException 凭证错误(密码错误)
        
        // 5. 认证
        subject.login(token);

        System.out.println( "是否认证成功: " + subject.isAuthenticated() );
        System.out.println( "是否有super这个角色: " +  subject.hasRole("super") );
        System.out.println( "是否有default这个角色: " +  subject.hasRole("default") );
        
        // 6. 授权
        System.out.println( "是否有user:select权限 " + subject.isPermitted("user:select"));
        System.out.println( "是否有user:delete权限 " + subject.isPermitted("user:delete"));
        System.out.println( "是否有user:update权限 " + subject.isPermitted("user:update"));
        System.out.println( "是否有user:insert权限 " + subject.isPermitted("user:insert"));

        
    }

}

** JdbcRealm: **

/**
 * 使用shiro提供的JdbcRealm进行认证(使用数据库数据)
 */
public class JdbcRealmTest {

    private static JdbcRealm jdbcRealm;
    
    static {
        jdbcRealm = new JdbcRealm();
        jdbcRealm.setDataSource(DBUtil.getDataSource());
        jdbcRealm.setPermissionsLookupEnabled(true);    // 使用JdbcRealm时要设置权限开关,默认为false
        
        // 自定义SQL语句(如果不设置自定义的SQL语句则按照JdbcRealm内置的模板SQL语句进行数据库操作,可以进入JdbcRealm查看)
        String sql = "select password from user where username = ?";
        jdbcRealm.setAuthenticationQuery(sql);

        String roleSql = "select role_name from user_role where username = ?";
        jdbcRealm.setUserRolesQuery(roleSql);
        
        String permissionSql = "select permission from role_permission where role_name = ?";
        jdbcRealm.setPermissionsQuery(permissionSql);
    }
    
    public static void main(String[] args) {

        // 1. 获取默认的SecurityManager
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(jdbcRealm);

        // 2. 设置到工具中
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        
        // 3. 获取主体
        Subject subject = SecurityUtils.getSubject();

        // 4. 创建token
        UsernamePasswordToken token = new UsernamePasswordToken(Users.ADMIN.getUsername(), Users.ADMIN.getPassword());
//        UsernamePasswordToken token = new UsernamePasswordToken(Users.TEST.getUsername(), Users.TEST.getPassword());
//        UsernamePasswordToken token = new UsernamePasswordToken("AAAA", "XXX"); //UnknownAccountException 没有改账号
//        UsernamePasswordToken token = new UsernamePasswordToken(Users.TEST.getUsername(), "XXX"); //IncorrectCredentialsException 凭证错误(密码错误)
        
        // 5. 认证
        subject.login(token);

        System.out.println( "是否认证成功: " + subject.isAuthenticated() );
        System.out.println( "是否有super这个角色: " +  subject.hasRole("super") );
        System.out.println( "是否有default这个角色: " +  subject.hasRole("default") );
        
        // 6. 授权
        System.out.println( "是否有user:select权限 " + subject.isPermitted("user:select"));
        System.out.println( "是否有user:delete权限 " + subject.isPermitted("user:delete"));
        System.out.println( "是否有user:update权限 " + subject.isPermitted("user:update"));
        System.out.println( "是否有user:insert权限 " + subject.isPermitted("user:insert"));
        
    }

}

自定义Realm(参考JdbcRealm)

** 辅助类: **

/**
 * MyRealm的辅助类(可以定义成内部类)
 */
public class UserDaoUtil {
    
    private UserDaoUtil(){ }
    
    private static Connection conn;

    static {
        try {
            conn = DBUtil.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    
    
    /**
     * 根据username获取SimpleAccount
     * @param username
     * @param realmName
     * @return
     */
    public static SimpleAccount getSimpleAccount(String username, String realmName) {
        
        PreparedStatement prepareStatement = null;
        ResultSet rs = null;
        SimpleAccount account = null;
        try {
            
            prepareStatement = conn.prepareStatement("select * from user where username = ?");
            prepareStatement.setString(1, username);
            rs = prepareStatement.executeQuery();
            rs.next();
            
            account = new SimpleAccount(rs.getString("username"), rs.getString("password"), realmName);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return account;
    }
    
    
    /**
     * 根据username获取role
     * @param username
     * @return
     */
    public static Set<String> getRoleNamesForUser(String username) {

        PreparedStatement prepareStatement = null;
        ResultSet rs = null;
        Set<String> roles = null;
        try {
            roles = new HashSet<>();
            prepareStatement = conn.prepareStatement("select * from user_role where username = ?");
            prepareStatement.setString(1, username);
            rs = prepareStatement.executeQuery();
            
            while(rs.next()) {
                roles.add( rs.getString("role_name") );
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return roles;
    }
    
    /**
     * 获取Permissions
     * @param username
     * @param roleNames
     * @return
     */
    public static Set<String> getPermissions(Set<String> roleNames) {
        
        PreparedStatement prepareStatement = null;
        ResultSet rs = null;
        Set<String> permissions = null;
        try {
            
            permissions = new HashSet<>();
            
            for (String roleName : roleNames) {
                
                prepareStatement = conn.prepareStatement("select * from role_permission where role_name = ?");
                prepareStatement.setString(1, roleName);
                rs = prepareStatement.executeQuery();
                
                while(rs.next()) {
                    permissions.add(rs.getString("permission"));
                }
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return permissions;
    }
    
}

** 自定义Realm: **

public class MyRealmTest {

    private static MyRealm myRealm;
    
    static {
        myRealm = new MyRealm();
    }   
    
    public static void main(String[] args) {
        
        // 1. 获取默认的SecurityManager
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(myRealm);

        // 2. 设置到工具中
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        
        // 3. 获取主体
        Subject subject = SecurityUtils.getSubject();

        // 4. 创建token
        UsernamePasswordToken token = new UsernamePasswordToken(Users.ADMIN.getUsername(), Users.ADMIN.getPassword());
//        UsernamePasswordToken token = new UsernamePasswordToken(Users.TEST.getUsername(), Users.TEST.getPassword());
//        UsernamePasswordToken token = new UsernamePasswordToken("AAAA", "XXX"); //UnknownAccountException 没有改账号
//        UsernamePasswordToken token = new UsernamePasswordToken(Users.TEST.getUsername(), "XXX"); //IncorrectCredentialsException 凭证错误(密码错误)
        
        // 5. 认证
        subject.login(token);
        System.out.println( "是否认证成功: " + subject.isAuthenticated() );
        
        System.out.println("----------------------------------------------------------------");
        
        System.out.println( "是否有super这个角色: " +  subject.hasRole("super") );
        System.out.println( "是否有default这个角色: " +  subject.hasRole("default") );
        
        System.out.println("----------------------------------------------------------------");
        
        // 6. 授权
        System.out.println( "是否有user:select权限 " + subject.isPermitted("user:select"));
        System.out.println( "是否有user:delete权限 " + subject.isPermitted("user:delete"));
        System.out.println( "是否有user:update权限 " + subject.isPermitted("user:update"));
        System.out.println( "是否有user:insert权限 " + subject.isPermitted("user:insert"));
    }

}

猜你喜欢

转载自www.cnblogs.com/tandi19960505/p/9671761.html