shiro加密流程:
——————————————————————————————————–图片仅供参考!
我是用的shiro与SSM整合:
首先是shiro配置文件:
<!-- 配置进行授权和认证的 Realm,要新增一个java类来实现,下面会有,class=包名.类名 -->
<bean id="myRealm" class="shiro.MyRealm">
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="MD5"></property> <!-- 加密算法的名称 -->
<property name="hashIterations" value="1024"></property> <!-- 配置加密的次数 -->
</bean>
</property>
</bean>
注册的controller:
/**
* 用于注册普通用户,以便登录
* @author Young
*
*/
@Controller
public class RegisterController {
private UserServiceI userService;
public UserServiceI getUserService() {
return userService;
}
@Autowired
public void setUserService(UserServiceI userService) {
this.userService = userService;
}
/**
* 使用md5盐值加密用于注册用户信息,盐即为用户Id;用户id与用户名相同
* @param user
* @return
*/
@RequestMapping(value = "registerUser",method = RequestMethod.POST)
public String registerUser(Sys_user user){
//加密密码
String password = new SimpleHash("MD5", user.getPassword(), user.getUserName(), 1024).toString();
user.setPassword(password);
userService.AddSys_User(user);
return "/jsp/user/registerSuccess";
}
}
userService.AddSys_User(user);将用户插入数据库;
登录的controller:
/**
* 登陆控制
* @return
*/
@RequestMapping(value = "login", method = RequestMethod.POST)
public String login(HttpServletRequest request,String userName,String password) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(userName,password);
try{
//调用subject.login(token)进行登录,会自动委托给securityManager,调用之前
subject.login(token);//会跳到我们自定义的realm中
return "/jsp/index/index";
}catch(Exception e){
e.printStackTrace();
System.out.println("用户名或密码错误");
//request.setAttribute("error", "用户名或密码错误");
return "/jsp/login/loginError";
}
}
自定义realm中进行登录认证
/**
* 用于登录认证,匹配数据库的信息.
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
String userName = (String) token.getPrincipal();// 获取用户名
// 根据用户输入的用户名在数据库进行匹配
Sys_user user = userService.getUserByName(userName);
//用户名存在则匹配密码
if (user != null) {
//1)principal:认证的实体信息,可以是userName,也可以是数据库表对应的用户的实体对象
Object principal = user.getUserName();
//2)credentials:数据库中的密码
Object credentials = user.getPassword();
//3)realmName:当前realm对象的name,调用父类的getName()方法即可
String realmName = getName();
//4)credentialsSalt盐值
ByteSource credentialsSalt = ByteSource.Util.bytes(userName);//使用用户名作为盐值
//根据用户的情况,来构建AuthenticationInfo对象,通常使用的实现类为SimpleAuthenticationInfo
//5)与数据库中用户名和密码进行比对,密码盐值加密,第4个参数传入realName。
SimpleAuthenticationInfo authcInfo = new SimpleAuthenticationInfo(principal, credentials,credentialsSalt,realmName);
return authcInfo;
} else {
return null;
}
}
通过用户的唯一标识得到 AuthenticationInfo 然后和 AuthenticationToken (用户名 密码)
部分源码如下:
/**
* Asserts that the submitted {@code AuthenticationToken}'s credentials match the stored account
* {@code AuthenticationInfo}'s credentials, and if not, throws an {@link AuthenticationException}.
*
* @param token the submitted authentication token
* @param info the AuthenticationInfo corresponding to the given {@code token}
* @throws AuthenticationException if the token's credentials do not match the stored account credentials.
*/
protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
CredentialsMatcher cm = getCredentialsMatcher();
if (cm != null) {
if (!cm.doCredentialsMatch(token, info)) {
//not successful - throw an exception to indicate this:
String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";
throw new IncorrectCredentialsException(msg);
}
} else {
throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " +
"credentials during authentication. If you do not wish for credentials to be examined, you " +
"can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");
}
}
具体的比较在doCredentialsMatch中实现;
具体的源码大佬们自己去看看,我还看不懂!
如果token与info的信息匹配的话,则登录成功!
此外就是为什么要盐值加密
因为可能存在多个用户的注册的密码时相同的,所以在密码hash过程中添加额外的随机值,即加盐。
由上面可以看出来我的盐值就是每个用户的用户Id,
SimpleHash参数为:加密算法名,加密源,盐,迭代次数
SimpleHash(String algorithmName, Object source, Object salt, int hashIterations)
//加密密码
String password = new SimpleHash("MD5", user.getPassword(), user.getUserName(), 1024).toString();