Shiro
是一个功能强大且易于使用的Java安全框架,它执行身份验证、授权、加密和会话管理。使用Shiro易于理解的API,您可以快速轻松地保护任何应用程序—从最小的移动应用程序到最大的web和企业应用程序
1.Shiro QuickStart
Subject currentUser = SecurityUtils.getSuject();//获取当前用户
Session session = currentUser.getSession();
//认证
currentUser.login(token);//通过抛出的异常来判断用户登录结果
//授权
currentUser.hasRole
currentUser.isPermitted
currentUser.isAuthenticated()
currentUser.isAuthenticated();
2.ShiroWeb
基础框架搭建:shiro配置三件套(模版代码)
@Configuration
public class ShiroConfig[
//1 Realm 代表系统资源
@Bean
public Realm myRealm(){
return new MyRealm();
}
//2 SecurityManager 流程控制
@Bean
public DefaultWebSecurityManager mySecurityManager(Realm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.SetRealm(myRealm);
return securityManager;
}
//3 ShiroFilterFactoryBean 请求过滤器
@Bean
public ShiroFilterFactoryBean getShiroFilterFatoryBean(DefaultWebSecurityManager mySecurityManger){
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(mySecurityManager);
return factoryBean;
}
}
3.实现验证登录功能
01.创建自己的Realm对象,继承AuthorizingRealm。
实现父类的doGetAuthenticationInfo认证方法
//登出的两种方式:
//01.
@RequestMapping("/logout")
public void logout(){
Subject currentUser = SecurityUtils.getSubject();
}
//02.使用shiro 提供的logout过滤器
filterMap.put("/common/logout","logout");
02.配置路径过滤器
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//自定义拦截器
Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>();
//访问权限配置
filtersMap.put("requestURL", getURLPathMatchingFilter());
shiroFilterFactoryBean.setFilters(filtersMap);
//拦截器.
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
// 配置不会被拦截的链接 顺序判断
List<String> urls = getIgnoredUrlsProperties().getUrls();
for (String url : urls) {
filterChainDefinitionMap.put(url, "anon");
}
filterChainDefinitionMap.put("/admin", "authc");
filterChainDefinitionMap.put("/admin/**", "requestURL");
filterChainDefinitionMap.put("/**", "anon");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
// 如果不设置默认会自动寻找Web工程根目录下的"/login"页面
shiroFilterFactoryBean.setLoginUrl("/login");
// 登录成功后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/");
//未授权界面;
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
return shiroFilterFactoryBean;
}
4 实现授权功能
01.控制主页上按钮的访问权限
currentUser.getPricipal() 来自于MyRealm中doGetAuthenticationInfo认证方法返回的SimpleAuthenticatiionInfo对象的第一属性。
02.控制后台资源路径的访问权限
方法1 硬编码的方式,自行判断权限。
方法2 使用shiro提供的perms过滤器,集中配置权限信息。
方法3 使用shiro提供的注解,实现方法级别的权限控制。
@RequiresAuthentication需要完成用户登录
@RequiresGuest 未登录用户可以访问,登录用户就不能访问。
@RequiresPermissions 需要有对应资源权限
@RequiresRoles 需要有对应的角色
@RequiresUser 需要完成用户登录并且实现了记住我功能
5 密码加密
shiro会获得一个CredentialsMatcher对象,来对密码进行比对。
想要用MD5方式进行加密:
Md5CredentialsMatcher已经过期,要使用HashedCredentialsMatcher并设定算法名。
HashedCredentialsMatcher
String hashAlgorithm 算法 ,对应Hash接口的实现类。MD5
int hashlterations Hash迭代的次数,比如MD5之后再次MD5
boolean hashSalted 已经过时,不用设置
boolean storedCredentialsHexEncoded 设置默认的true
加盐加密
需要在认证返回的认证信息SimpleAuthenticationInfo中,指定需要加的盐Salt。
这样算出来的密文才可以和数据库中的密文进行比对。
6 多realm认证要实现用户名和手机号都可以登录的功能
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws
AuthenticationException{
assertRealmsConfigured();
Collection<Realm> realms = getRealms();
if(realms.size()== 1){
return doSingleRealmAuthentication(realms.iterator().next(),authenticationToken);
}else{
return doMultiRealmAuthentication(realms,authenticationToken);
}
}
可以定义多个Realm完成不同的认证功能。
我们通过增加一个MobileRealm,就实现了按照手机号也可以登录的功能。
多Realm的认证策略
AuthenticationStrategy接口 有三个实现类
AllSuccessfulStragegy 需要所有Realm认证成功,才能最终认证成功。
AtLeastOneSuccessfulStrategy 至少有一个 Realm认证成功,才能最终认证成功。
FirstSuccessfulStrategy 第一个Realm认证成功后即返回认证成功,不再进行后面的Realm认证。
7 记住我功能
token.setRememberMe(true)
记住我功能对应了 默认的user过滤器。
怎么设置记住我的时长,以及记到哪里。
securityManager.setRememberMeManager(rememberMeManager);管理RememberMe的数据
8 会话管理
securityManager.setRememberManager(sessionManager);实现会话管理
9 认证缓存
MemeoryConstrainedCacheManager cacheManager = new MemoryConstrainedCacheManager();
securityManager.setCacheManager(cacheManager);
记住我功能,会话管理以及认证缓存,都可以通过扩展对应的manager接口的方式,实现自己的灵魂扩展,比如将信息共享到redis。