1.身份认证流程
- 获取当前的 Subject. 调用 SecurityUtils.getSubject();
- 测试当前的用户是否已经被认证. 即是否已经登录. 调用 Subject 的 isAuthenticated()
- 若没有被认证, 则把用户名和密码封装为 UsernamePasswordToken 对象
- 首先调用 Subject.login(token) 进行登录,其会自动委托给SecurityManager
- SecurityManager 负责真正的身份验证逻辑;它会委托给Authenticator 进行身份验证;
- Authenticator 才是真正的身份验证者,Shiro API 中核心的身份认证入口点,此处可以自定义插入自己的实现;
- Authenticator 可能会委托给相应的 AuthenticationStrategy 进行多 Realm 身份验证,默认 ModularRealmAuthenticator 会调用AuthenticationStrategy 进行多 Realm 身份验证;
- Authenticator 会把相应的 token 传入 Realm,从 Realm 获取身份验证信息,如果没有返回/抛出异常表示身份验证失败了。此处可以配置多个Realm,将按照相应的顺序及策略进行访问。
- 自定义 Realm 的方法, 从数据库中获取对应的记录, 返回给 Shiro.
2.Realm类
- 授权需要继承 AuthorizingRealm 类, 并实现其 doGetAuthorizationInfo 方法
- AuthorizingRealm 类继承自 AuthenticatingRealm, 但没有实现 AuthenticatingRealm 中的
doGetAuthenticationInfo, 所以认证和授权只需要继承 AuthorizingRealm 就可以了. 同时实现他的两个抽象方法.
如何把一个字符串加密为 MD5?
替换当前 Realm 的 credentialsMatcher 属性. 直接使用 HashedCredentialsMatcher 对象, 并设置加密算法即可
<bean id="jdbcRealm" class="com.liang.realm.ShiroRealm">
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="MD5"></property>
<!-- 加密次数 -->
<property name="hashIterations" value="10"></property>
</bean>
</property>
</bean>
为什么使用 MD5 盐值加密?
即使两个人的明文密码一样,加密后的密码也是不一样的
如何做到盐值加密?
1). 在 doGetAuthenticationInfo 方法返回值创建 SimpleAuthenticationInfo 对象的时候, 需要使用
SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName) 构造器
2). 使用 ByteSource.Util.bytes() 来计算盐值.
3). 盐值需要唯一: 一般使用随机字符串或 user id
4). 可以使用 new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations); 来计算盐值加密后的密码的值.
ByteSource credentialsSalt=ByteSource.Util.bytes(username);//盐值,一般使用随机字符串或 user id,即使两个人的明文密码一样,加密后的密码也是不一样的
3.AuthenticationStrategy认证策略
- AuthenticationStrategy 接口的默认实现:
- FirstSuccessfulStrategy:只要有一个 Realm 验证成功即可,只返回第 一个 Realm
身份验证成功的认证信息,其他的忽略; - AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,和
FirstSuccessfulStrategy 不同,将返回所有Realm身份验证成功的认证信 息; - AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有
Realm身份验证成功的认证信息,如果有一个失败就失败了。 - ModularRealmAuthenticator 默认是 AtLeastOneSuccessfulStrategy 策略