shiro安全框架的三大核心
1,Subject(主体)
相当于shiro的主题,shiro的核心API就是Subject,Subject代表的就是当前的用户,这个用户不是指具体的某一个人,可以说与当前应用交互的任何东西都是Subject,与Subject的所有交互都会委托给SecurityManager来执行,可以理解为Subject只是一个充当门面的,真正的幕后老大是SecurityManager,SecurityManager才是实际的执行者。
2,SecurityManager(安全管理器)
subject的幕后操作的就是SecurityManager
所有与安全有关的操作都会与SecurityManager进行交互,并且SecurityManager管理者所有的Subject,可以看出它才是Shiro的核心,它负责与Shiro的其他组件进行交互,它相当于SpringMvc中的dispatcherServlet(前端控制器)的角色。
3,Realm
就好比mybatis的datasource,所有的用户信息的账号密码都存储在Realm中,Realm中存储安全数据(用户,角色,权限)
Shiro从Realm获取安全数据(用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法,也需要从Realm获取用户的角色\权限来判断用户是否能进行一系列操作。可以把Realm看作DataSource数据源.
整合Realm
整合其实就是shiro中的三大核心逐步整合到容器中去,首先第一步,整合realm,自定义UserRealm继承自AuthorizingRealm这个类,里面主要有认证和授权的两个步骤,将用户的业务类也注入进来
@Autowired
UserService userService;
授权
首选来看授权的逻辑,授权就是给用户分配自己设置权限
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("执行了授权");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//添加权限
info.addStringPermission("user:add");
//拿到当前登录的对象
Subject subject = SecurityUtils.getSubject();
User currentUser = (User) subject.getPrincipal();//拿到user对象
//设置当前用户的权限
info.addStringPermission(currentUser.getPerms());
//return info;
return info;
}
认证
密码的认证是shiro做的,在方法的逻辑中只用做用户的认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了认证");
//用户名密码,数据库中取
// String name="root";
// String password="123456";
//连接真实的数据库
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
// if(!userToken.getUsername().equals(name)){
// return null;//抛出异常
// }
User user = userService.queryByName(userToken.getUsername());
if (null == user) {
return null;
}
//密码认证,shiro做
return new SimpleAuthenticationInfo("user", user.getPwd(), "");
}
整合SecurityManage
在安全管理器的整合中需要注入刚才整合的UserRealm,所以首先编写一个配置类,在配置类中注入Bean,这个配置类加上@Configuration注解
首选注入UserRelam的Bean
@Bean(name = "Realm")
public UserRealm userRealm() {
return new UserRealm();
}
同样,如果需要整合一些方言的话,将ShiroDialect这个类也注入进去
//整合ShiroDialect(方言):用来整合shiro和thymeleaf
@Bean
public ShiroDialect getShiroDialect() {
return new ShiroDialect();
}
接着,就是经典的两个Bean,其中的依赖关系如下图所示:
这另外的两个Beand的依赖关系,看源码如图所示,两个方法对应的是层级的依赖,从底向上分别重写相应的方法就可以
默认的安全管理器需要注入userRealm,同理内置过滤器的整合也是这样,最后剩下的两个Bean整合结果如下:
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
//添加shiro的内置过滤器
/*
anon:无需认证就可以访问
authc: 必须认证了才可以访问
user: 必须拥有 记住我功能才能用
perms: 拥有对某个资源的权限才可以访问:
role: 拥有某个角色权限才能访问
filterMap.put("/user/add","anno");
filterMap.put("/user/update","authc");
*/
//1,拦截
Map<String, String> filterMap = new LinkedHashMap<>();
//2,授权 正常情况下,未授权会跳到401
filterMap.put("user/add", "perms[user:add]");
filterMap.put("user/update", "perms[user:update]");
//后面的会把前面的覆盖
filterMap.put("/user/*", "authc");
bean.setFilterChainDefinitionMap(filterMap);
//设置登录的请求
bean.setLoginUrl("/toLogin");
//设置未授权页面
bean.setUnauthorizedUrl("/noauth");
return bean;
}
@Bean(name = "defaultWebSecurityManager")
//DafauleWebSecurityManage
public DefaultWebSecurityManager getDefaultWebSecurityManage(@Qualifier("Realm") UserRealm Realm) {
DefaultWebSecurityManager securityManage = new DefaultWebSecurityManager();
//关联UserRealm
securityManage.setRealm(Realm);
return securityManage;
}
就这样,基本完成了Shiro的相关整合,剩下的就是需要在项目中熟练使用