Shiro是apache旗下一个开源安全框架,它将软件系统的安全认证相关的功能抽取出来,实现用户身份认证,权限授权、加密、会话管理等功能,组成了一个通用的安全认证框架,使用shiro就可以非常快速的完成认证、授权等功能的开发,降低系统成本。
课后了解:Spring security 安全框架
在概念层,Shiro 架构包含三个主要的理念:Subject,SecurityManager和 Realm。
1)Subject(主体):与软件交互的一个特定的实体(用户、第三方服务等)。
2)SecurityManager(安全管理器) :Shiro 的核心,用来协调管理组件工作。
3)Authenticator(认证管理器):负责执行认证操作
4)Authorizer(授权管理器):负责授权检测
5)SessionManager(会话管理):负责创建并管理用户 Session 生命周期,提供一个强有力的 Session 体验。
6)SessionDAO:代表 SessionManager 执行 Session 持久(CRUD)动作,它允许任何存储的数据挂接到 session 管理基础上。
7)CacheManager(缓存管理器):提供创建缓存实例和管理缓存生命周期的功能
8)Cryptography(加密管理器):提供了加密方式的设计及管理。
9)Realms(领域对象):是shiro和你的应用程序安全数据之间的桥梁。
简述:
1)系统调用subject的login方法将用户信息提交给SecurityManager
2)SecurityManager将认证操作委托给认证器对象Authenticator
3)Authenticator将身份信息传递给Realm。
4)Realm访问数据库获取用户信息然后对信息进行封装并返回。
5)Authenticator 对realm返回的信息进行身份认证。
详述:
以用户名密码验证为例,当浏览器客户端向服务器发送AJAX异步请求,请求服务器处理验证用户输入的用户名和密码,
当请求传入Tomcat,通过Tomcat的过滤器****到达前端控制器的时候,前端控制器截取请求的url,在HandlerMapping里找对应的map集合中的entry元素,找到后穿过springMVC的拦截器到达后端控制器Controller,在Controller里使用SecorityUtils获取一个Subject,subject里面有一个login方法,但是调用login方法必须传入一个token类型的参数,这时候我们想到AJAX里面传过来的username和password正好可以封装在一个UsernamePasswordtoken里面,所以我们这样写
UsernamePasswordToken tokensubjec = new UsernamePasswordToken(username,password);
Subject subject = SecurityUtils.Subject();
subject.login(token);
当我们写完这句subject.login(token);
系统底层会帮我们从配置文件读取我们配置的SecurityManager以及相关配置,并将token传过去,会找到anthenticator(认证管理器),anthenticator根据SecurityManager里面配置的realm,找到realm。我们要做的就是在这之前一定要确保该realm已经存在,否则会找不到,在realm中我们将传过来token进行向下造型回usernamepasswordtoken,
然后将里面的username取出来,传递到数据层,让数据层根据username从用户名中查询具体用户所有信息,查询完毕我们使用一个SimpleAuthenticationInfo进行信息封装,new一个该对象的时候我们要传入四个参数,第一个是身份信息,我们一般传入从dao数据层查到的用户信息,但是要注意这里写入的类型和授权的时候取数据的类型要对应,如果只写用户名则取数据的时候用字符串接收,第二个参数是加密后的密码,我们已经查到,第三个参数是指定类型的salt,其实和我们通过数据层查到的salt是一样的只不过需要的类型不一致,需要做一步转型即可,第四个参数是realm的名字,表示本类直接用this.getName();然后将我们new出来的SimpleAuthenticationInfo对象的实例返回给认证管理器,认证管理器会自动帮我们认证。
如下图所示
概述:
1)系统调用subject相关方法将用户信息(例如isPermitted)递交给SecurityManager
2)SecurityManager将权限检测操作委托给Authorizer对象
3)Authorizer将用户信息委托给realm.
4)Realm访问数据库获取用户权限信息并封装。
5) Authorizer对用户授权信息进行判定。
@Bean("securityManager")
public DefaultWebSecurityManager newDefaultWebSecurityManager(
AuthorizingRealm userRealm){
DefaultWebSecurityManager sManager=
new DefaultWebSecurityManager();
//此时必须保证realm对象已经存在了
sManager.setRealm(userRealm);
return sManager;
}
@Bean("shiroFilterFactoryBean")
public ShiroFilterFactoryBean newShiroFilterFactoryBean(
SecurityManager securityManager){//shiro 包
ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
bean.setSecurityManager(securityManager);
//当此用户是一个非认证用户,需要先登陆进行认证
bean.setLoginUrl("/doLoginUI.do");
LinkedHashMap fcMap=
new LinkedHashMap<>();
fcMap.put("/bower_components/**","anon");//anon表示允许匿名访问
fcMap.put("/build/**", "anon");
fcMap.put("/dist/**","anon");
fcMap.put("/plugins/**","anon");
fcMap.put("/doLogin.do","anon");
fcMap.put("/doLogout.do","logout");
fcMap.put("/**", "authc");//必须授权才能访问
bean.setFilterChainDefinitionMap(fcMap);
return bean;
}
@Bean("lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor newLifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
}
@DependsOn(value="lifecycleBeanPostProcessor")
@Bean
public DefaultAdvisorAutoProxyCreator newDefaultAdvisorAutoProxyCreator(){
return new DefaultAdvisorAutoProxyCreator();
}
@Bean
public AuthorizationAttributeSourceAdvisor newAuthorizationAttributeSourceAdvisor(
SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor bean=
new AuthorizationAttributeSourceAdvisor();
bean.setSecurityManager(securityManager);
return bean;
}
3.3.Shiro 核心过滤器配置
在注解启动类中,重写onStartup方法,完成过滤器的注册
@Override
public void onStartup(ServletContext servletContext)
throws ServletException {
System.out.println("onStartup");
//super.onStartup(servletContext);
registerContextLoaderListener(servletContext);
registerFilter(servletContext);
registerDispatcherServlet(servletContext);
}
private void registerFilter(ServletContext servletContext) {
//注册Filter对象
//项目没有web.xml并且此filter不是自己写的,所以需要用这种配置方式
FilterRegistration.Dynamic dy=
servletContext.addFilter("filterProxy",
DelegatingFilterProxy.class);
dy.setInitParameter("targetBeanName","shiroFilterFactoryBean");
dy.addMappingForUrlPatterns(
null,//EnumSet
false,"/*");//url-pattern
}
web.xml
CGB-JT-SYS-V1.01
shiroFilter
org.springframework.web.filter.DelegatingFilterProxy
targetBeanName
shiroFilterFactory
shiroFilter
/*
frontController
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:spring-configs.xml
1
frontController
*.do