我正在尝试保护我的企业网络应用程序!
我必须限制资源。
由于我已将所有文件存储在我的数据库(用户和角色)中,因此我不会创建fileRealm或将任何用户的凭证存储在(Glassfish)服务器中。而且,我正在使用jBCrypt来加密用户的密码,所以我不能使用标准的jdbcRealm。
我如何保护我的资源?
我在考虑自定义jdbcRealm,这是正确的方法吗?如何创建和使用它?
现有的一些框架可以帮助我吗?
先感谢您。
最佳答案
我建议您使用框架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;
}
}