1.功能:
- 身份认证(核心)
- 资源授权(核心)
- 记住我
- session 管理
- 加密
2.组件
- subject:应用层代码和shrio代码的中间组件。
- 核心功能放在realm
- realm注册到securityManager管理
- shiroFilterFactoryBean,访问策略,不同的url,不同的访问策略
- 方言管理器组件
- 实现注解的组件
- session管理器组件
- 记住我组件
3.流程
一、身份认证流程
- 页面输入用户名和密码 ---
- 跳转到登录控制器----
- 调用service---
- 得到subject----
- 封装一个令牌------
- 装载用户名和密码----
- subject.login(令牌) ----
- realm的身份认证方法
- 取用户名,通过用户名查找数据库的user信息----
- 查到了封装一个身份验证1器----
- 用身份验证器和令牌比对----
- 成功则登录成功授权。
二、资源授权流程
- 页面输入用户名和密码
- 登录控制器
- 调用service
- 得到subject
- 通过subject取调用subject.checkRoles()找到身份
- 等待登录成功,成功后,进行页面跳转,或者页面访问,放入封装信息
- 遇到页面shrio标签或者注解
- realm资源授权方法,从认证中获取封装的信息,
- 从数据库查询当前用户的角色列表
- 在去数据库查询每个角色拥有的资源列表
- 将角色列表和资源列表封装到资源授权器
- 再去用资源授权器去和页面的标签或者注解比对,有权限则访问成功,反之,抛出异常
三、实现
1.servlet实现(不讲)
2.spring boot 实现
1.引入相应的依赖,pom
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.4.1</version>
</dependency>
<!-- thymeleaf 对 shiro 的扩展包,支持页面书写 shiro 标签 -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
2.配置
1.application.properties
#开启shiro
shiro.web.enabled=true
3.shrio组件
1.编写Realm配置类
/**
* MyRealm:资源授权和身份验证
*/
@Component
public class MyRealm extends AuthorizingRealm {
//1.将MyRealm注册为bean,因为要调用service
@Autowired
private UserService userService;
@Autowired
private RoleService roleService;
@Autowired
private ResourceService resourceService;
//资源授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
//资源授权器
SimpleAuthorizationInfo authorization = new SimpleAuthorizationInfo();
//1.realm资源授权方法,从认证中获取封装的信息,
User user = (User) principal.getPrimaryPrincipal();
//2. 从数据库查询当前用户的角色列表,并转载到资源授权器里
List<Role> roles = roleService.getRolesByUserId(user.getId());
//把当前用户的角色列表加入进资源授权器
roles.stream().forEach(item ->{
authorization.addRole(item.getRoleName());
//3.在去数据库查询每个角色拥有的资源列表,并转载到资源授权器里
List<Resource> resources = (List<Resource>) resourceService.getResourceById(item.getId());
//4.将角色列表和资源列表封装到资源授权器
resources.stream().forEach(item2 ->{
authorization.addStringPermission(item2.getPermission());
});
});
return authorization;
}
//身份验证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//1.获取用户名
String userName = (String) token.getPrincipal();
//2.通过用户名查找数据库的user信息,调用service
User user = userService.getUserByUserName(userName);
if (null == user){
throw new UnknownAccountException("User name is not exit.");
}
//3.封装身份验证器,new SimpleAuthenticationInfo(Object principal, Object credentials, String realmName);
return new SimpleAuthenticationInfo(user,user.getPassword(),getName());
}
}
2.编写配置shrio组件类:config/shrio/ShiroConfig
- 组件安全管理器: securityManager
- shiro 过滤器工厂, ShiroFilterFactoryBean,需要注入安全管理器
- -配置 shiro 过滤器工厂:ShiroFilterFactoryBean
- -----------------
- -拦截权限
- anon:匿名访问,无需登录 ---- AnonymousFilter
- authc:登录后才能访问 ---- FormAuthenticationFilter
- user:登录过能访问 ---- UserFilter
- logout:登出 ---- LogoutFilter
- ------------------
- URL匹配风格
- ?:匹配一个字符,如 /admin? 将匹配 /admin1,但不匹配 /admin 或 /admin/
- *:匹配零个或多个字符串,如 /admin* 将匹配 /admin 或/admin123,但不匹配 /admin/1
- **:匹配路径中的零个或多个路径,如 /admin/** 将匹配 /admin/a 或 /admin/a/b
- -----------------------
- -方法名不能乱写,如果我们定义为别的名称,又没有添加注册过滤器的配置,
- -那么 shiro 会加载 ShiroWebFilterConfiguration 过滤器,
- -该过滤器会寻找 shiroFilterFactoryBean,找不到会抛出异常
- 注册shiro方言,让 thymeleaf 支持 shiro 标签
- DefaultAdvisorAutoProxyCreator, Advisor 代理类生成器
- 创建 AuthorizationAttributeSourceAdvisor,扫描 Shiro 注解
- 代码
@Configuration
public class ShrioConfig {
@Autowired
private MyRealm myRealm;
//组件安全管理器: securityManager
@Bean
public SecurityManager securityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
return securityManager;
}
/**
* -配置 shiro 过滤器工厂:ShiroFilterFactoryBean
* -----------------
* -拦截权限
* anon:匿名访问,无需登录 ---- AnonymousFilter
* authc:登录后才能访问 ---- FormAuthenticationFilter
* user:登录过能访问 ---- UserFilter
* logout:登出 ---- LogoutFilter
* ------------------
* URL匹配风格
* ?:匹配一个字符,如 /admin? 将匹配 /admin1,但不匹配 /admin 或 /admin/
* *:匹配零个或多个字符串,如 /admin* 将匹配 /admin 或/admin123,但不匹配 /admin/1
* **:匹配路径中的零个或多个路径,如 /admin/** 将匹配 /admin/a 或 /admin/a/b
* -----------------------
* -方法名不能乱写,如果我们定义为别的名称,又没有添加注册过滤器的配置,
* -那么 shiro 会加载 ShiroWebFilterConfiguration 过滤器,
* -该过滤器会寻找 shiroFilterFactoryBean,找不到会抛出异常
*/
//组件:shiro 过滤器工厂, ShiroFilterFactoryBean,需要注入安全管理器
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(){
ShiroFilterFactoryBean filterFactory = new ShiroFilterFactoryBean();
//1.注入安全管理器
filterFactory.setSecurityManager(securityManager());
//2.设置登录页面和登录成功页面
filterFactory.setLoginUrl("/login");
filterFactory.setSuccessUrl("/test/thymeleafTest");
//3.设置其余地址的访问规则,放在map中,key:通配符,value:访问策略
/**
* anon:匿名访问,无需登录 ---- AnonymousFilter
* authc:登录后才能访问 ---- FormAuthenticationFilte
* user:登录过能访问 ---- UserFilter
* logout:登出 ---- LogoutFilter
*/
Map<String, String> filterMap = new LinkedHashMap<>();
//匿名策略:全部开放 anon:
// 登录注册
filterMap.put("/login","anon");
filterMap.put("/register","anon");
// 静态资源
filterMap.put("/favicon.ico","anon");
filterMap.put("/css/**","anon");
filterMap.put("/images/**","anon");
filterMap.put("/js/**","anon");
filterMap.put("/vendors/**","anon");
filterMap.put("/static/**","anon");
// 测试模块
filterMap.put("/test/**","anon");
// api开发
filterMap.put("/api/**","anon");
//非匿名策略
filterMap.put("/**","authc");
//4.返回过滤器工厂
filterFactory.setFilterChainDefinitionMap(filterMap);
return filterFactory;
}
/**
* - 注册shiro方言,让 thymeleaf 支持 shiro 标签
*/
@Bean
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}
/**
* DefaultAdvisorAutoProxyCreator, Advisor 代理类生成器
*/
@Bean
@DependsOn({"lifecycleBeanPostProcessor"})
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
/**
* - 创建 AuthorizationAttributeSourceAdvisor,扫描 Shiro 注解
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor;
}
}
4.实现
1.身份认证实现
@Override
@Transactional
public Result<User> login(User user) {
//1. 得到subject----
Subject subject = SecurityUtils.getSubject();
//2. 封装一个令牌,装载用户名和密码------
UsernamePasswordToken token = new UsernamePasswordToken(
user.getUserName(),
MD5Util.getMD5(user.getPassword()));
//3. subject.login(令牌)----
try {
//令牌,身份认证和资源授权
subject.login(token);
subject.checkRole();
//获取当前用户,并设置到session中
//获取MyRealm认证返回的user
User temp = (User) subject.getPrincipal();
//返回apache的session
Session session = subject.getSession();
session.setAttribute("user",temp);
return new Result<>(Result.ResultStatus.SUCCESS.code,"SUCCESS",temp);
} catch (Exception e) {
e.printStackTrace();
LOGGER.debug(e.getMessage());
return new Result<>(Result.ResultStatus.FAILD.code,e.getMessage());
}
}
2.资源授权
- 整套系统的权限规则
- admin ----最高权限
- manager --------除了删除之外都能干
- staff ---------查看共性信息,访问测试模块、修改自己的信息
- 为多用户分配角色,资源细腻
- admin账户---admin角色 ----拥有删除资源
- manager账户 ----mannager角色 -----没有删除功能
- staff账户 ------staff角色 -----查看共性信息,访问测试模块、修改自己的信息