1. 程式人生 > >Shiro學習筆記(四)--- CustomRealm

Shiro學習筆記(四)--- CustomRealm

一、簡介

CustomRealm(自定義Realm)是通過仿造JdbcRealm,繼承AuthrizingRealm,

重寫doGetAuthenticationInfo(AuthenticationToken token)【認證】和 doGetAuthorizationInfo(PrincipalCollection principalCollection)【授權】方法

二、理解

自定義的Realm,主要注意一下幾個步驟:

  1. 首先繼承並實現類AuthorizingRealm的方法。其中方法

    doGetAuthenticationInfo 主要做認證操作,即可以通過獲取其中的

    使用者名稱,查詢出相應的密碼,然後將使用者名稱與密碼一併返回,shiro會自動根據傳入的使用者名稱與密碼與此Realm返回的使用者名稱和密碼作比對,返回你想要的結果。同理doGetAuthorizationInfo主要是用來做角色與許可權的驗證,也是通過使用者名稱,從資料庫中查詢到相應的角色或者許可權的資料並返回一個Simple的授權類,授權系統會根據傳入的引數與返回的結果集對比,存在返回true不存在則拋異常。

  2. 兩者方法只能獲取使用者名稱稱,通過使用者名稱稱連線資料庫獲取其他資訊。這裡只是做資料準備操作,並不做判斷是否傳入的值與其相符的操作,此操作在此之後進行。

  3. 根據兩者的返回物件分別返回Simple型別的物件。認證的物件需要將你獲取的使用者名稱和密碼放到構造方法中。授權的物件需要你set到相應的方法中。

三、程式碼(參考官方JdbcRealm的實現)

public class JdbcRealm extends AuthorizingRealm {
    protected static final String DEFAULT_AUTHENTICATION_QUERY = "select password from users where username = ?";
    protected static final String DEFAULT_SALTED_AUTHENTICATION_QUERY = "select password, password_salt from users where username = ?";
    protected static final String DEFAULT_USER_ROLES_QUERY = "select role_name from user_roles where username = ?";
    protected static final String DEFAULT_PERMISSIONS_QUERY = "select permission from roles_permissions where role_name = ?";
    private static final Logger log = LoggerFactory.getLogger(JdbcRealm.class);
    protected DataSource dataSource;
    protected String authenticationQuery = "select password from users where username = ?";
    protected String userRolesQuery = "select role_name from user_roles where username = ?";
    protected String permissionsQuery = "select permission from roles_permissions where role_name = ?";
    protected boolean permissionsLookupEnabled = false;
    protected JdbcRealm.SaltStyle saltStyle;

    public JdbcRealm() {
        this.saltStyle = JdbcRealm.SaltStyle.NO_SALT;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void setAuthenticationQuery(String authenticationQuery) {
        this.authenticationQuery = authenticationQuery;
    }

    public void setUserRolesQuery(String userRolesQuery) {
        this.userRolesQuery = userRolesQuery;
    }

    public void setPermissionsQuery(String permissionsQuery) {
        this.permissionsQuery = permissionsQuery;
    }

    public void setPermissionsLookupEnabled(boolean permissionsLookupEnabled) {
        this.permissionsLookupEnabled = permissionsLookupEnabled;
    }

    public void setSaltStyle(JdbcRealm.SaltStyle saltStyle) {
        this.saltStyle = saltStyle;
        if (saltStyle == JdbcRealm.SaltStyle.COLUMN && this.authenticationQuery.equals("select password from users where username = ?")) {
            this.authenticationQuery = "select password, password_salt from users where username = ?";
        }

    }

    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken upToken = (UsernamePasswordToken)token;
        String username = upToken.getUsername();
        if (username == null) {
            throw new AccountException("Null usernames are not allowed by this realm.");
        } else {
            Connection conn = null;
            SimpleAuthenticationInfo info = null;

            try {
                String salt;
                try {
                    conn = this.dataSource.getConnection();
                    String password = null;
                    salt = null;
                    switch(this.saltStyle) {
                    case NO_SALT:
                        password = this.getPasswordForUser(conn, username)[0];
                        break;
                    case CRYPT:
                        throw new ConfigurationException("Not implemented yet");
                    case COLUMN:
                        String[] queryResults = this.getPasswordForUser(conn, username);
                        password = queryResults[0];
                        salt = queryResults[1];
                        break;
                    case EXTERNAL:
                        password = this.getPasswordForUser(conn, username)[0];
                        salt = this.getSaltForUser(username);
                    }

                    if (password == null) {
                        throw new UnknownAccountException("No account found for user [" + username + "]");
                    }

                    info = new SimpleAuthenticationInfo(username, password.toCharArray(), this.getName());
                    if (salt != null) {
                        info.setCredentialsSalt(Util.bytes(salt));
                    }
                } catch (SQLException var12) {
                    salt = "There was a SQL error while authenticating user [" + username + "]";
                    if (log.isErrorEnabled()) {
                        log.error(salt, var12);
                    }

                    throw new AuthenticationException(salt, var12);
                }
            } finally {
                JdbcUtils.closeConnection(conn);
            }

            return info;
        }
    }

    private String[] getPasswordForUser(Connection conn, String username) throws SQLException {
        boolean returningSeparatedSalt = false;
        String[] result;
        switch(this.saltStyle) {
        case NO_SALT:
        case CRYPT:
        case EXTERNAL:
            result = new String[1];
            break;
        case COLUMN:
        default:
            result = new String[2];
            returningSeparatedSalt = true;
        }

        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            ps = conn.prepareStatement(this.authenticationQuery);
            ps.setString(1, username);
            rs = ps.executeQuery();

            for(boolean foundResult = false; rs.next(); foundResult = true) {
                if (foundResult) {
                    throw new AuthenticationException("More than one user row found for user [" + username + "]. Usernames must be unique.");
                }

                result[0] = rs.getString(1);
                if (returningSeparatedSalt) {
                    result[1] = rs.getString(2);
                }
            }
        } finally {
            JdbcUtils.closeResultSet(rs);
            JdbcUtils.closeStatement(ps);
        }

        return result;
    }

    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        if (principals == null) {
            throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
        } else {
            String username = (String)this.getAvailablePrincipal(principals);
            Connection conn = null;
            Set<String> roleNames = null;
            Set permissions = null;

            try {
                conn = this.dataSource.getConnection();
                roleNames = this.getRoleNamesForUser(conn, username);
                if (this.permissionsLookupEnabled) {
                    permissions = this.getPermissions(conn, username, roleNames);
                }
            } catch (SQLException var11) {
                String message = "There was a SQL error while authorizing user [" + username + "]";
                if (log.isErrorEnabled()) {
                    log.error(message, var11);
                }

                throw new AuthorizationException(message, var11);
            } finally {
                JdbcUtils.closeConnection(conn);
            }

            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
            info.setStringPermissions(permissions);
            return info;
        }
    }

    protected Set<String> getRoleNamesForUser(Connection conn, String username) throws SQLException {
        PreparedStatement ps = null;
        ResultSet rs = null;
        LinkedHashSet roleNames = new LinkedHashSet();

        try {
            ps = conn.prepareStatement(this.userRolesQuery);
            ps.setString(1, username);
            rs = ps.executeQuery();

            while(rs.next()) {
                String roleName = rs.getString(1);
                if (roleName != null) {
                    roleNames.add(roleName);
                } else if (log.isWarnEnabled()) {
                    log.warn("Null role name found while retrieving role names for user [" + username + "]");
                }
            }
        } finally {
            JdbcUtils.closeResultSet(rs);
            JdbcUtils.closeStatement(ps);
        }

        return roleNames;
    }

    protected Set<String> getPermissions(Connection conn, String username, Collection<String> roleNames) throws SQLException {
        PreparedStatement ps = null;
        LinkedHashSet permissions = new LinkedHashSet();

        try {
            ps = conn.prepareStatement(this.permissionsQuery);
            Iterator var6 = roleNames.iterator();

            while(var6.hasNext()) {
                String roleName = (String)var6.next();
                ps.setString(1, roleName);
                ResultSet rs = null;

                try {
                    rs = ps.executeQuery();

                    while(rs.next()) {
                        String permissionString = rs.getString(1);
                        permissions.add(permissionString);
                    }
                } finally {
                    JdbcUtils.closeResultSet(rs);
                }
            }
        } finally {
            JdbcUtils.closeStatement(ps);
        }

        return permissions;
    }

    protected String getSaltForUser(String username) {
        return username;
    }

    public static enum SaltStyle {
        NO_SALT,
        CRYPT,
        COLUMN,
        EXTERNAL;

        private SaltStyle() {
        }
    }
}