我正在努力收集必要的信息,以实现我的目标。我的目标很简单,利用Shiro进行身份验证和授权。我希望在Java Web应用程序上下文中部署shiro。我希望用户能够登录并检查MySQL数据库的凭据。我想为密码实现SHA256哈希。我并不喜欢,所以我使用传统的JSP和Servlet。
我正在使用的技术:Apache Tomcat 7,Apache Shiro,MySQL,Apache Web Server
我在这里走在正确的轨道上吗?
/WEB-INF/shiro.ini
[main]
# Using my JNDI resource for JDBC
dataSource = org.apache.shiro.jndi.JndiObjectFactory
dataSource.resourceName = jdbc/myResource
dataSource.resourceRef = true
jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.dataSource = $dataSource
# Using Pass Thru security filter so I can manage login.
authc = org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter
authc.loginUrl = /login
authc.successUrl = /my-account
# Use default service and password matcher
passwordService = org.apache.shiro.authc.credential.DefaultPasswordService
passwordMatcher = org.apache.shiro.authc.credential.PasswordMatcher
passwordMatcher.passwordService = $passwordService
#Realms section
# Finally, set the matcher on a realm that requires password matching for account authentication:
# myRealm.credentialsMatcher = $passwordMatcher
# ???
[users]
[roles]
[urls]
/login = authc
/logout = logout
问题1:在我的“#Use service service and password matcher”部分下,这是配置Shiro与SHA256进行密码比较的正确方法吗?
问题2:在我的“#Realms部分”部分下,我不明白该怎么做。您能否建议CredentialsMatcher代码应该是什么样子?
关于问题2,我注意到CredentialsMatcher interface文档,建议使用HashedCrendentialsMatcher进行比较。我应该创建一个使用HashedCredentialsMatcher的新java类吗?然后我会在shiro.ini文件中引用该类作为我的“领域”?
新帐户注册
创建新用户时,我想加密密码。我选择使用Shiro框架提供的加密工具。我将使用DefaultPasswordService对象实例来加密我的用户密码。结果值存储在数据库中。
String rawPassword = "secret";
DefaultPasswordService passwordService = new DefaultPasswordService();
String encryptedPassword = passwordService.encryptPassword(rawPassword);
String hash = passwordService.hashPassword(rawPassword).toString();
//Create the user
User user = new User();
user.setUsername(username)
user.setEncryptedPassword(encryptedPassword);
user.setHash(hash);
//Save to Database
userDAO.save(user);
//Log the user in immediately after new account created.
try {
UsernamePasswordToken userToken = new UsernamePasswordToken(username, rawPassword);
SecurityUtils.getSubject().login(userToken);
} catch (UnknownAccountException uae) {
LogMe.s(this.getClass().getName(), "Log error specific message here...", uae);
} catch (IncorrectCredentialsException ice) {
LogMe.s(this.getClass().getName(), "Log error specific message here...", ice);
} catch (LockedAccountException lae) {
LogMe.s(this.getClass().getName(), "Log error specific message here...", lae);
} catch (ExcessiveAttemptsException eae) {
LogMe.s(this.getClass().getName(), "Log error specific message here...", eae);
} catch (AuthenticationException ae) {
LogMe.s(this.getClass().getName(), "Log error specific message here...", ae);
}catch (Exception ex) {
LogMe.s(this.getClass().getName(), "Log error specific message here...", ex);
}
问题3:就我的“新帐户注册”逻辑而言,这是一种可接受的方法吗?建议?问另一种方式,我正确配置?
问题4:在MySQL中存储哈希值时,是否可以使用hashPassword()将其转换为字符串?哈希值字段是否有建议的长度:例如VARCHAR(15)?
用户登录
我选择在登录过程中手动验证用户身份。我可以从Servlet中检索POST中的用户名/密码。我最终将建立AJAX登录机制,这就是我选择这种方法的原因。这是我难倒的地方。以下是两个片段。第一个是提交给我的servlet的html表单。第二个片段是执行身份验证的方法。
/登录
<form name="loginform" action="login.do" method="post">
<p>Username</p>
<input type="text" name="username" />
<p>Password</p>
<input type="password" name="password" />
<input type="submit" value="Login" />
</form>
登录方式
//Getters and Setters omitted for username, rawPassword.
private void login() {
if (!SecurityUtils.getSubject().isAuthenticated()) {
String fallbackUrl = "/user-account-default-page";
try {
UsernamePasswordToken userToken = new UsernamePasswordToken(username, rawPassword);
SecurityUtils.getSubject().login(userToken);
//Take advantage of the auto redirect to the page user wanted. Or default to the fallbackUrl
WebUtils.redirectToSavedRequest(request, response, fallbackUrl);
} catch (UnknownAccountException uae) {
LogMe.s(this.getClass().getName(), "Log error specific message here...", uae);
} catch (IncorrectCredentialsException ice) {
LogMe.s(this.getClass().getName(), "Log error specific message here...", ice);
} catch (LockedAccountException lae) {
LogMe.s(this.getClass().getName(), "Log error specific message here...", lae);
} catch (ExcessiveAttemptsException eae) {
LogMe.s(this.getClass().getName(), "Log error specific message here...", eae);
} catch (AuthenticationException ae) {
LogMe.s(this.getClass().getName(), "Log error specific message here...", ae);
}catch (Exception ex) {
LogMe.s(this.getClass().getName(), "Log error specific message here...", ex);
}
}
}
/注销
由于shiro.ini文件中的代码片段,Shiro会注销用户?通过将URL“/ logout”设置为logout,Shrio会将用户注销。它是否正确?
# Section of the shiro.ini file
[urls]
/logout = logout
感谢您提供的所有见解。我希望这个问题不是霸道,也许将来会帮助别人。另请注意,我最初在shiro forums上提出了这个问题。