Shiro学习笔记
认证
思路
- 获取当前的Subject,调用SecurityUtils.getSubject()方法;
- 判断当前用户是否被认证,即是否已经登陆,调用Subject的isAuthenticated()方法进行判断;
- 若没有认证,则把用户名和密码封装成UsernamePasswordToken对象;
- 创建表单页面
- 把请求提交到SpringMVC的Handler;
- 获取用户名和密码
- 执行登陆:调用Subject的login()方法;
- 继承AuthorizingRealm类,重写认证doGetAuthenticationInfo方法
- 从UsernamePasswordToken中取出前端传入的用户名和密码;
- 将从数据中查出的用户名和密码信息封装成AuthenticationInfo对象返回(一般为Simple)
- 由shiro中的credentialsMatcher自动完成密码的比对;
/**
* 认证方法
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String username = token.getUsername();
//根据用户名从数据库查询出用户名和密码
//如果用户不存在,则给出提示
//如果用户存在,根据用户的信息, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo
//认证的实体信息. 可以是 username, 也可以是数据表对应的用户的实体类对象.
Object principal = username;
//密码
Object credentials = null;
//realName:当前realm的name,调用父类的getName()获取
String realmName = getName();
//shiro会把返回的SimpleAuthenticationInfo对象和UsernamePasswordToken中的对象进行比对
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, realmName);
return info;
}
多Realm认证
配置
1、配置ModularRealmAuthenticator对象;并设置认证策略;
2、SecurityManager中有authenticator属性,将ModularRealmAuthenticator对象设置进去;
3、SecurityManager中有realms属性,将多个realm传进去即可;
1. 配置 SecurityManager!-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="authenticator" ref="authenticator"></property>
<property name="realms">
<list>
<ref bean="jdbcRealm"/>
<ref bean="secondRealm"/>
</list>
</property>
<property name="rememberMeManager.cookie.maxAge" value="10"></property>
</bean>
<bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
<!--指定认证策略-->
<property name="authenticationStrategy">
<bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"></bean>
</property>
</bean>
认证策略
认证执行流程分析
授权
授权思路
1、继承AuthorizingRealm类,重写doGetAuthorizationInfo方法,在其中实现授权的逻辑;
2、在controller中的方法上使用@RequiresPermissions注解表明需要的权限;
- 在controller上使用注解;
- 在代码中通过hasRole()、hasPermitted()等方法进行判断,
3、请求controller中的方法时,如果方法上有权限注解,则会走重写doGetAuthorizationInfo方法发的授权逻辑,判断用户是否具有权限;
ShiroFilter中可以通过下面的方式:配置哪些页面需要受保护. ,以及访问这些页面需要的权限。
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/login.jsp"/>
<property name="successUrl" value="/list.jsp"/>
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
<!-- 配置哪些页面需要受保护. 以及访问这些页面需要的权限.
1). anon 可以被匿名访问
2). authc 必须认证(即登录)后才可能访问的页面.
3). logout 登出.
4). roles 角色过滤器
-->
<property name="filterChainDefinitions">
<value>
/index.jsp = anon
/login.jsp = anon
/shiro/login = anon
/shiro/logout = logout
/user.jsp = roles[user]
/admin.jsp = roles[admin]
# everything else requires authentication:
/** = authc
</value>
</property>
</bean>
但是这种方式是有缺陷的,一般我们会从数据库中读取权限,然后进行设置,所以可以对上面的配置方式进行改造,通过工厂方法创建bean
public class FilterChainDefinitionMapBuilder {
public LinkedHashMap<String, String> buildFilterChainDefinitionMap(){
LinkedHashMap<String, String> map = new LinkedHashMap<>();
map.put("index.jsp", "anon");
map.put("/login.jsp", "anon");
map.put("/shiro/login", "anon");
map.put("/shiro/logout", "logout");
map.put("/user.jsp", "authc,roles[user]");
map.put("/admin.jsp", "authc,roles[admin]");
map.put("/list.jsp", "user");
map.put("/**", "authc");
return map;
}
}
<!--配置 ShiroFilter,id 必须和 web.xml 文件中配置的 DelegatingFilterProxy 的 <filter-name> 一致. 若不一致, 则会抛出: NoSuchBeanDefinitionException. 因为 Shiro 会来 IOC 容器中查找和 <filter-name> 名字对应的 filter bean.-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/login.jsp"/>
<property name="successUrl" value="/list.jsp"/>
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
<property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"></property>
</bean>
<!-- 配置一个 bean, 该 bean 实际上是一个 Map. 通过实例工厂方法的方式 -->
<bean id="filterChainDefinitionMap"
factory-bean="filterChainDefinitionMapBuilder" factory-method="buildFilterChainDefinitionMap"></bean>
<bean id="filterChainDefinitionMapBuilder"
class="com.example.factory.FilterChainDefinitionMapBuilder"></bean>
常用权限注解:
参考
- Shiro视频
- 若依开源项目