我最近写了一篇关于这个的博客:
你可以告诉tomcat的jdbcrealm在密码上使用摘要算法,如sha-256,并保存哈希而不是明文密码。
假设您的用户实体如下所示:
@Entity
@Table(name = "cr_users")
public class UserDetails{
@Id
@GeneratedValue
private long id;
private String name;
private String passwordHash;
@ManyToMany
private Set<Group> groups;
}
通过服务创建新用户时,可以使用 MessageDigest 创建密码哈希:
public UserDetails createNewUser(String username,String passwd,Set<Group> groups){
UserDetails u=new UserDetails();
u.setname(username);
u.setGroups(groups);
u.setPassword(createHash(passwd));
return u;
}
public String createHash(String data){
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(password.getBytes());
byte byteData[] = digest.digest();
//convert bytes to hex chars
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteData.length; i++) {
sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
}
由于SHA-256将始终为相同的输入产生相同的哈希值,因此您可以告诉tomcat的JDBCRealm使用此算法来验证密码。
<Realm className="org.apache.catalina.realm.JDBCRealm"
driverName="org.postgresql.Driver"
connectionURL="jdbc:postgresql://localhost:5432/mydb"
connectionName="myuser" connectionPassword="mypass"
userTable="tc_realm_users" userNameCol="username" userCredCol="passwordhash"
userRoleTable="tc_realm_groups" roleNameCol="groupname"
digest="sha-256"/>
问题是tomcat会期望用户表有不同的格式,如下所示:
+----------------------+ +-------------------+
| tc_realm_users | | tc_realm_groups |
+----------------------+ +-------------------+
| username varchar | | username varchar |
| passwordhash varchar | | groupname varchar |
+----------------------+ +-------------------+
如果你的用户数据模型适合你很幸运,但我的Hibernate生成的表看起来像这样:
+----------------------+ +-------------------+ +--------------------+
| cr_users | | cr_groups | | cr_users_cr_groups |
+----------------------+ +-------------------+ +--------------------+
| id long | | id long | | cr_users_id long |
| name varchar | | name varchar | | groups_id long |
| passwordhash varchar | +-------------------+ +--------------------+
+----------------------+
所以我使用SQL创建了一个视图,它具有预期的格式,并从我的webapps用户数据中提取数据:
create view tc_realm_groups as
select
cr_users.name as username,
groups.name as groupname
from cr_users
left join (
select
cr_users_cr_groups.cr_users_id,cr_groups.name
from cr_groups
left join
cr_users_cr_groups
on cr_users_cr_groups.groups_id=cr_groups.id
) as groups on groups.cr_users_id=id;
create view tc_realm_users as
select
name as username
from cr_users;
有了这个,tomcat能够再次验证/授权我已经存在的用户数据,并在上下文中写入数据,以便我可以在我的泽西岛(JSR-311)资源中使用它:
public Response getEvent(@Context SecurityContext sc,@PathParam("id") long id) {
log.debug("auth: " + sc.getAuthenticationScheme());
log.debug("user: " + sc.getUserPrincipal().getName()); // the username!
log.debug("admin-privileges: " + sc.isUserInRole("webapp-admin"));
return Response.ok(“auth success”).build();
}
还有其他一些 Realm 实现:
- JDBCRealm
- DataSourceRealm
- JNDIRealm
- 用户数据库Realm
- 记忆现实
- 亚斯雷亚姆
- 组合现实
- 锁定现实
一些链接: