【问题标题】:how to create custom JDBCrealm?如何创建自定义 JDBCrealm?
【发布时间】:2017-03-12 17:40:21
【问题描述】:

我正在尝试保护我的企业网络应用程序! 我必须限制资源。

由于我已经全部存储在我的数据库(用户和角色)中,我不会在(Glassfish)服务器中创建 fileRealm 或存储任何用户的凭据。此外,我使用 jBCrypt 来加密用户的密码,所以我不能使用标准的 jdbcRealm。

如何保护我的资源?

我正在考虑自定义 jdbcRealm,这是正确的方法吗?我如何创建和使用它?

一些现有的框架可以帮助我吗?

提前谢谢你。

【问题讨论】:

    标签: java security encryption glassfish jdbcrealm


    【解决方案1】:

    我建议您使用框架Apache Shiro。配置文件如下

    [main]
    
    sha256Matcher = org.apache.shiro.authc.credential.HashedCredentialsMatcher
    sha256Matcher.hashAlgorithmName = SHA-256
    sha256Matcher.hashIterations=1
    # base64 encoding
    sha256Matcher.storedCredentialsHexEncoded = false
    
    #datasource type
    ds = org.apache.shiro.jndi.JndiObjectFactory
    
    #datasourcename
    ds.resourceName = cfresource
    
    #datasourcetype
    ds.requiredType = javax.sql.DataSource
    
    
    
    
    #configuring jdbc realm
    jdbcRealm = com.connectifier.authc.realm.CustomJDBCRealm
    jdbcRealm.credentialsMatcher = $sha256Matcher
    jdbcRealm.dataSource=$ds
    jdbcRealm.userRolesQuery=select name from role where email = ? and isactive=1
    jdbcRealm.authenticationQuery=select hash, salt from user where email = ?
    jdbcRealm.permissionsLookupEnabled=false
    securityManager.realms = $jdbcRealm
    #login url
    authc.loginUrl = /
    
    #page to redirected to after logout
    logout.redirectUrl = /
    
    #page to where to land after login
    authc.successUrl = /
    
    #username parameter name in the loginform
    authc.usernameParam = username
    
    #password parameter name in the loginform
    authc.passwordParam = password
    
    #rememberme parameter name in the loginform
    authc.rememberMeParam=rememberme
    
    #cacheManager = org.apache.shiro.cache.ehcache.EhCacheManager
    #securityManager.cacheManager = $cacheManager
    #jdbcRealm.authenticationCachingEnabled = true
    
    [urls]
    # The /login.jsp is not restricted to authenticated users (otherwise no one could log in!), but
    # the 'authc' filter must still be specified for it so it can process that url's
    # login submissions. It is 'smart' enough to allow those requests through as specified by the
    # shiro.loginUrl above.
    
    /* = anon
    

    CustomJDBCRealm 覆盖 JDBCRealm 在下面

    package com.connectifier.authc.realm;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    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.SimpleAuthenticationInfo;
    import org.apache.shiro.authc.UnknownAccountException;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.codec.Base64;
    import org.apache.shiro.realm.jdbc.JdbcRealm;
    import org.apache.shiro.util.ByteSource;
    import org.apache.shiro.util.JdbcUtils;
    import org.apache.shiro.util.SimpleByteSource;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * @author kiranchowdhary
     * 
     *         Application specific JDBC realm. If required override methods of {@link JdbcRealm} to load users, roles and
     *         permissions from database.
     * 
     *         Do not override configuration in code if it can be done via shiro.ini file.
     */
    public class CustomJDBCRealm extends JdbcRealm {
    
        private static final Logger log = LoggerFactory.getLogger(JdbcRealm.class);
    
        public CustomJDBCRealm() {
            super();
            setSaltStyle(SaltStyle.COLUMN);
        }
    
        /**
         * overriding the method which is in JdbcRealm. If SaltStyle is COLUMN, then gets String salt value from database
         * and forms salt byte array of type {@link ByteSource} with decoded string salt value and sets it to salt value of
         * AuthenticationInfo.
         */
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    
            UsernamePasswordToken upToken = (UsernamePasswordToken) token;
            String username = upToken.getUsername();
    
            // Null username is invalid
            if (username == null) {
                throw new AccountException("Null usernames are not allowed by this realm.");
            }
    
            Connection conn = null;
            SimpleAuthenticationInfo info = null;
            try {
                conn = dataSource.getConnection();
    
                String password = null;
                String salt = null;
                switch (saltStyle) {
                case NO_SALT:
                case CRYPT:
                case EXTERNAL:
                    return super.doGetAuthenticationInfo(token);
                case COLUMN:
                    String[] queryResults = getPasswordForUser(conn, username);
                    password = queryResults[0];
                    salt = queryResults[1];
                    break;
                }
    
                if (password == null) {
                    throw new UnknownAccountException("No account found for user [" + username + "]");
                }
    
                info = new SimpleAuthenticationInfo(username, password.toCharArray(), getName());
    
                if (salt != null) {
                    info.setCredentialsSalt(new SimpleByteSource(Base64.decode(salt)));
                }
    
            } catch (SQLException e) {
                final String message = "There was a SQL error while authenticating user [" + username + "]";
                if (log.isErrorEnabled()) {
                    log.error(message, e);
                }
    
                // Rethrow any SQL errors as an authentication exception
                throw new AuthenticationException(message, e);
            } finally {
                JdbcUtils.closeConnection(conn);
            }
    
            return info;
        }
    
        private String[] getPasswordForUser(Connection conn, String username) throws SQLException {
    
            String[] result;
            boolean returningSeparatedSalt = false;
            switch (saltStyle) {
            case NO_SALT:
            case CRYPT:
            case EXTERNAL:
                result = new String[1];
                break;
            default:
                result = new String[2];
                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.");
                    }
    
                    result[0] = rs.getString(1);
                    if (returningSeparatedSalt) {
                        result[1] = rs.getString(2);
                    }
    
                    foundResult = true;
                }
            } finally {
                JdbcUtils.closeResultSet(rs);
                JdbcUtils.closeStatement(ps);
            }
    
            return result;
        }
    }
    

    【讨论】:

    • 非常感谢,我在发布问题后才开始使用 shiro...现在我有太多问题,0 票,我不能发布其他问题:(
    猜你喜欢
    • 1970-01-01
    • 2021-04-16
    • 2014-08-05
    • 2015-12-08
    • 2016-07-10
    • 1970-01-01
    • 2011-12-29
    • 2020-05-30
    • 1970-01-01
    相关资源
    最近更新 更多