All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.kaizen4j.shiro.realm.SimpleJdbcRealm Maven / Gradle / Ivy

The newest version!
package com.github.kaizen4j.shiro.realm;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.config.ConfigurationException;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.JdbcUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author liuguowen
 */
public class SimpleJdbcRealm extends JdbcRealm {

    private static final Logger logger = LoggerFactory.getLogger(SimpleJdbcRealm.class);

    /**
     * 账户已锁定
     */
    private static final String ACCOUNT_LOCKED = "1";

    /**
     * The default query used to retrieve account data for the user.
     */
    private static final String CUSTOM_AUTHENTICATION_QUERY = "select password, locked from sys_user where username = ?";

    /**
     * The default query used to retrieve account data for the user when {@link #saltStyle} is COLUMN.
     */
    private static final String CUSTOM_SALTED_AUTHENTICATION_QUERY = "select password, salt, locked from sys_user where username = ?";

    /**
     * The default query used to retrieve the roles that apply to a user.
     */
    private static final String CUSTOM_USER_ROLES_QUERY = "select sys_role.name from sys_user "
            + "join sys_user_roles on sys_user.id = sys_user_roles.user_id join sys_role on sys_user_roles.role_id = sys_role.id "
            + "where sys_user.username = ? and sys_role.available = 1";

    /**
     * The default query used to retrieve permissions that apply to a particular role.
     */
    private static final String CUSTOM_PERMISSIONS_QUERY = "select sys_resource.permission from sys_role_resources "
            + "join sys_resource on sys_role_resources.resource_id = sys_resource.id join sys_role on sys_role.id = sys_role_resources.role_id "
            + "where sys_role.name = ? and sys_resource.available = 1 and sys_resource.type = 'REST'";

    public SimpleJdbcRealm() {
        this.authenticationQuery = CUSTOM_AUTHENTICATION_QUERY;
        this.userRolesQuery = CUSTOM_USER_ROLES_QUERY;
        this.permissionsQuery = CUSTOM_PERMISSIONS_QUERY;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // Null username are invalid
        if (principals == null) {
            throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
        }

        String username = (String) getAvailablePrincipal(principals);

        Connection conn = null;
        Set roleNames = null;
        Set permissions = null;
        try {
            conn = dataSource.getConnection();

            // Retrieve roles and permissions from database
            roleNames = getRoleNamesForUser(conn, username);
            if (permissionsLookupEnabled) {
                permissions = getPermissions(conn, username, roleNames);
            }

        } catch (SQLException e) {
            final String message = "There was a SQL error while authorizing user [" + username + "]";
            if (logger.isErrorEnabled()) {
                logger.error(message, e);
            }

            // Rethrow any SQL errors as an authorization exception
            throw new AuthorizationException(message, e);
        } finally {
            JdbcUtils.closeConnection(conn);
        }

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

    }

    @Override
    public void setSaltStyle(SaltStyle saltStyle) {
        this.saltStyle = saltStyle;
        if (saltStyle == SaltStyle.COLUMN && authenticationQuery.equals(CUSTOM_AUTHENTICATION_QUERY)) {
            authenticationQuery = CUSTOM_SALTED_AUTHENTICATION_QUERY;
        }
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        String username = upToken.getUsername();

        // Null username is invalid
        if (StringUtils.isBlank(username)) {
            throw new AccountException("Null username are not allowed by this realm.");
        }

        Connection conn = null;
        SimpleAuthenticationInfo info;
        try {
            conn = dataSource.getConnection();
            String[] queryResults = getPasswordFromUser(conn, username);

            String password = null;
            String salt = null;
            String locked = null;
            switch (saltStyle) {
                case NO_SALT:
                    password = queryResults[0];
                    locked = queryResults[1];
                    break;
                case CRYPT:
                    throw new ConfigurationException("Not implemented yet");
                case COLUMN:
                    password = queryResults[0];
                    salt = queryResults[1];
                    locked = queryResults[2];
                    break;
                case EXTERNAL:
                    password = queryResults[0];
                    locked = queryResults[1];
                    salt = getSaltForUser(username);
                    break;
                default:
                    throw new ConfigurationException("Not salt implemented pass yet");
            }

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

            if (ACCOUNT_LOCKED.equals(locked)) {
                throw new LockedAccountException("Locked account for user [" + username + "]");
            }

            info = new SimpleAuthenticationInfo(username, password.toCharArray(), getName());

            if (salt != null) {
                if (saltStyle == SaltStyle.COLUMN && saltIsBase64Encoded) {
                    info.setCredentialsSalt(new SimpleByteSource(Base64.decode(salt)));
                } else {
                    info.setCredentialsSalt(new SimpleByteSource(salt));
                }
            }
        } catch (SQLException e) {
            final String message = "There was a SQL error while authenticating user [" + username + "]";
            if (logger.isErrorEnabled()) {
                logger.error(message, e);
            }

            // Rethrow any SQL errors as an authentication exception
            throw new AuthenticationException(message, e);
        } finally {
            JdbcUtils.closeConnection(conn);
        }

        return info;
    }

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

        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            ps = conn.prepareStatement(authenticationQuery);
            ps.setString(1, username);

            // Execute query
            rs = ps.executeQuery();

            // Loop over results - although we are only expecting one result, since usernames should be unique
            boolean foundResult = false;
            while (rs.next()) {
                // Check to ensure only one row is processed
                if (foundResult) {
                    throw new AuthenticationException(
                            "More than one user row found for user [" + username + "]. Usernames must be unique.");
                }

                // password
                result[0] = rs.getString(1);
                if (returningSeparatedSalt) {
                    // salt
                    result[1] = rs.getString(2);
                    // locked
                    result[2] = rs.getString(3);
                } else {
                    // locked
                    result[1] = rs.getString(2);
                }

                foundResult = true;
            }
        } finally {
            JdbcUtils.closeResultSet(rs);
            JdbcUtils.closeStatement(ps);
        }

        return result;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy