Shiro框架概述
Shiro将软件系统的安全认证相关的功能抽取出来,实现用户身份认证,权限授权、加密、会话管理等功能,组成了一个通用的安全认证框架。用户在进行资源访问时,对用户进行权限控制
Shiro架构概要
- Subject : 主体对象,负责提交用户认证和授权信息
- SecurityManager : 安全管理器,负责认证,授权等业务实现
- Realm : 领域对象,负责从数据层获取业务数据
Shiro详细架构
- Subject(主体) 与软件交互的一个特定的实体
- SecurityManager(安全管理器) Shiro核心,协调管理组件工作
- Authentjactor(授权管理器) 负责检测授权
- Session Manager(会话管理) 创建并管理用户Session生命周期
- SessionManager(缓存管理器)提供创建缓存实例,管理缓存生命周期
- Cryptography(加密管理器):提供了加密方式的设计及管理。
- Realms(领域对象):是shiro和你的应用程序安全数据之间的桥梁。
Shiro认证拦截实现(filter拦截器)
- (1).Spring整合Shiro时,需要先添加依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.5.3</version>
</dependency>
- (2).Shiro核心对象配置,SpringBoot项目中,没有提供Shiro自动配置所以要手动配置
package com.cy.pj.common.config;
/**@Configuration 注解描述的类为一个配置对象,
* 此对象也会交给spring管理
*/
@Configuration
public class SpringShiroConfig {
}
- (3).在Shiro配置类中添加SecurityManager配置(安全管理器)
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager sManager = new DefaultWebSecurityManager();
return sManager;
}
- (4).在Shiro配置类中添加ShiroFilterFactoryBean(过滤器工厂对象)对象的配置。通过此对象设置资源匿名访问、认证访问。
@Bean
public ShiroFilterFactoryBean shiroFilterFactory(SecurityManager securityManager) {
ShiroFilterFactoryBean fBean=new ShiroFilterFactoryBean();
fBean.setSecurityManager(securityManager);
//设置需要进行认证的登陆页面
fBean.setLoginUrl("/doLoginUI");
//设置过滤规则(有顺序,允许匿名访问的放在上面)
LinkedHashMap<String,String> filterMap=new LinkedHashMap<>();
filterMap.put("/bower_components/**","anon");//anno为shiro框架定义,会对应一个过滤器对象,这里表示允许匿名访问
filterMap.put("/build/**","anon");
filterMap.put("/dist/**","anon");
filterMap.put("/plugins/**","anon");
filterMap.put("/user/doLogin", "anon");//登陆操作允许匿名访问
//filterMap.put("/doIndexUI", "anon");//首页页面允许匿名访问
filterMap.put("/doLogout", "logout");//logout为登出操作,此操作执行时会进入登陆页面
//filterMap.put("/**", "authc");//authc为设置需要认证访问的资源
filterMap.put("/**", "user");//user表示可以通过用户端提交的cookie信息进行认证
fBean.setFilterChainDefinitionMap(filterMap);
return fBean;
}
Shiro登录页面呈现
1.服务端Controller实现
当服务单拦截到用户请求以后,需要先判定此请求是否被认证,如果没认证应该先跳转到登录页面
在Controller中添加一个呈现登录页面的方法
@RequestMapping("doLoginUI")
public String doLoginUI(){
return "login";
}
2.修改SpringShiroConfig配置类中的ShiroFilterFactorybean(Shiro拦截器工厂对象)添加登录url的设置
@Bean
public ShiroFilterFactoryBean shiroFilterFactory (
@Autowired SecurityManager securityManager) {
ShiroFilterFactoryBean sfBean=
new ShiroFilterFactoryBean();
sfBean.setSecurityManager(securityManager);
sfBean.setLoginUrl("/doLoginUI");
//定义map指定请求过滤规则(哪些资源允许匿名访问,
哪些必须认证访问)
LinkedHashMap<String,String> map=
new LinkedHashMap<>();
//静态资源允许匿名访问:"anon"
map.put("/bower_components/**","anon");
map.put("/modules/**","anon");
map.put("/dist/**","anon");
map.put("/plugins/**","anon");
//除了匿名访问的资源,其它都要认证("authc")后访问
map.put("/**","authc");
sfBean.setFilterChainDefinitionMap(map);
return sfBean;
}
Shiro框架认证业务实现
身份认证就是判断用户是否是系统的合法用户,对用户的身份信息的认证
- 系统调用subject的login方法将用户信息提交给SecurityManager
- SecurityManager将认证操作委托给认证器对象Authenticator
- Authenticator将用户输入的身份信息传递给Realm
- Realm访问数据库获取用户信息然后对信息进行封装并返回。
- Authenticator 对realm返回的信息进行身份认证。
1.Dao接口定义
在SysUserDao接口中,添加根据用户名获取用户对象的方法
SysUser findUserByUserName(String username);
2.Mapper定义
基于用户名获取用户对象的方法
<select id="findUserByUserName"resultType="com.cy.pj.sys.entity.SysUser">
select *
from sys_users
where username=#{username}
</select>
3.Service接口及实现
本模块的业务在Realm类型的对象中进行实现,我们编写realm时,要继承
AuthorizingRealm并重写相关方法,完成认证及授权业务数据的获取及封装
3.1设置凭证匹配器即匹配密码(与用户添加时使用相同的加密算法)
@Override
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
//构建凭证匹配对象
HashedCredentialsMatcher cMatcher= new HashedCredentialsMatcher();
//设置加密算法
cMatcher.setHashAlgorithmName("MD5");
//设置加密次数
cMatcher.setHashIterations(1);
super.setCredentialsMatcher(cMatcher);
}
3.2完成认证数据的获取封装,系统底层会将认证数据传递给认证管理器,由认证管理器来完成认证操作
认证操作完成后会将结果返回给认证管理器
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)throws AuthenticationException {
//1.获取用户名(用户页面输入)
UsernamePasswordToken upToken=(UsernamePasswordToken)token;
String username=upToken.getUsername();
//2.基于用户名查询用户信息
SysUser user=sysUserDao.findUserByUserName(username);
//3.判定用户是否存在
if(user==null)
throw new UnknownAccountException();
//4.判定用户是否已被禁用。
if(user.getValid()==0)
throw new LockedAccountException();
//5.封装用户信息
ByteSource credentialsSalt=ByteSource.Util.bytes(user.getSalt());
//记住:构建什么对象要看方法的返回值
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(
user,//principal (身份)
user.getPassword(),//hashedCredentials
credentialsSalt, //credentialsSalt
getName());//realName
//6.返回封装结果
return info;//返回值会传递给认证管理器(后续
//认证管理器会通过此信息完成认证操作)
}
3.3修改Realm 需要在SpringShiroConfig配置类中注入安全管理器对象(Secyritymanager)对象
@Bean
public SecurityManager securityManager(Realm realm) {
DefaultWebSecurityManager sManager=
new DefaultWebSecurityManager();
sManager.setRealm(realm);
return sManager;
}
3.4.Controller类实现
Controller主要用于获取用户输入的用户名等信息,然后提交给Shiro进行认证
封装完成的用户信息会传递给Shioro的安全管理器(SecurityManger),安全管理器会传递给认证管理器,认证管理器会传递给Realm
@RequestMapping("doLogin")
public JsonResult doLogin(String username,String password){
//1.获取Subject对象
Subject subject=SecurityUtils.getSubject();
//2.通过Subject提交用户信息,交给shiro框架进行认证操作
//2.1对用户进行封装
UsernamePasswordToken token=new UsernamePasswordToken(username, password);//身份信息//凭证信息
//2.2对用户信息进行身份认证
subject.login(token);
//分析:
//1)token会传给shiro的SecurityManager
//2)SecurityManager将token传递给认证管理器
//3)认证管理器会将token传递给realm
return new JsonResult("login ok");
}
3.5修改ShiroFilterFactory的配置
认证路径匿名访问
@Bean
public ShiroFilterFactoryBean shiroFilterFactory (
SecurityManager securityManager) {
ShiroFilterFactoryBean sfBean=
new ShiroFilterFactoryBean();
sfBean.setSecurityManager(securityManager);
//假如没有认证请求先访问此认证的url
sfBean.setLoginUrl("/doLoginUI");
//定义map指定请求过滤规则(哪些资源允许匿名访问,哪些必须认证访问)
LinkedHashMap<String,String> map=
new LinkedHashMap<>();
//静态资源允许匿名访问:"anon"
map.put("/bower_components/**","anon");
map.put("/build/**","anon");
map.put("/dist/**","anon");
map.put("/plugins/**","anon");
map.put("/user/doLogin","anon"); //authc表示,除了匿名访问的资源,其它都要认证("authc")后才能访问访问
map.put("/**","authc");
sfBean.setFilterChainDefinitionMap(map);
return sfBean;
}