简介
Shiro是一款属于apache的轻量级框架,是开源项目。常见Java安全管理框架:
Spring Security
特点:
基于Spring开发,契合度高
功能多,社区资源丰富
使用较复杂
Shiro:
特点
不依赖于Spring
简单易上手
功能和社区资源比SpringSecurity稍弱
Shio拥有三大核心组件:
Subject:主体。一般指用户;
SecurityManager:安全管理器,管理所有的Subject,可以配合内部安全组件,类似于springmvc中的DispatcherServlet;
realms:用于进行用户权限信息的认证,一般需要自己实现;
如何使用
首先导入依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.7.0</version>
</dependency>
再配置ShiroConfig
@Configuration
public class ShiroConfig {
@Resource
private ITGradeService gradeService;
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//将自定义的realm交给SecurityManager管理
securityManager.setRealm(jwtRealm());
return securityManager;
}
/**
* 配置Shiro的Web过滤器,拦截浏览器请求并交给SecurityManager处理
*
* @return
*/
@Bean
public ShiroFilterFactoryBean webFilter(SecurityManager securityManager) {
// ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 用自定义的FactoryBean来设置过滤器
ShiroFilterFactoryBean shiroFilterFactoryBean = new RestShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();
filters.put("perms", new RestAuthorizationFilter());
filters.put("authc", new ShiroFormAuthenticationFilter());
List<TGradeBean> functionInfoBeans = gradeService.list();
Map filterChainMap = ShiroUtil.loadFilterChainMap(functionInfoBeans);
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
return shiroFilterFactoryBean;
}
public class ShiroUtil {
public static Map loadFilterChainMap(List<TGradeBean> gradeBeans){
//配置拦截链 使用LinkedHashMap,因为LinkedHashMap是有序的,shiro会根据添加的顺序进行拦截
// Map<K,V> K指的是拦截的url V值的是该url是否拦截
Map<String, String> filterChainMap = new LinkedHashMap<String, String>(16);
//authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问,先配置anon再配置authc。
filterChainMap.put("/users/login", "anon");
filterChainMap.put("/swagger-ui.html", "anon");
filterChainMap.put("/webjars/**", "anon");
filterChainMap.put("/swagger-resources/**", "anon");
filterChainMap.put("/v2/api-docs", "anon");
filterChainMap.put("/users/token", "authc");
for (TGradeBean gradeBean:gradeBeans) {
if (gradeBean.getGradeUrl() != null && !gradeBean.getGradeUrl().equals("")) {
String url = gradeBean.getGradeUrl();
if(gradeBean.getGradeMethod() != null && !gradeBean.getGradeMethod().equals("")){
url += "==" + gradeBean.getGradeMethod();
}
filterChainMap.put(url,"perms["+gradeBean.getGradeName()+"]");
}
}
filterChainMap.put("/**", "authc");
return filterChainMap;
}
再配置realm
public class CustomRealm extends AuthorizingRealm {
@Resource
private ITUserService userService;
@Resource
private ITGradeService gradeService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取当前登录的用户
TUserBean userBean = (TUserBean) principalCollection.getPrimaryPrincipal();
//通过SimpleAuthenticationInfo做授权
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
// 得到当前用户包含的所有角色
List<TRoleBean> roleBeans = userBean.getRoleBeans();
List<TGradeBean> gradeBeans = gradeService.selectByRoleId(roleBeans);
for (TRoleBean role : roleBeans) {
//添加角色
simpleAuthorizationInfo.addRole(role.getName());
}
for (TGradeBean gradeBean : gradeBeans) {
//添加权限
simpleAuthorizationInfo.addStringPermission(gradeBean.getGradeName());
}
return simpleAuthorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 身份认证的操作
//1.获取用户输入的账号
String username = (String) authenticationToken.getPrincipal();
//2.通过username从数据库中查找到user实体
TUserBean userBean = userService.findByCode(username);
if (userBean == null) {
return null;
}
//3.通过SimpleAuthenticationInfo做身份处理
SimpleAuthenticationInfo simpleAuthenticationInfo =
new SimpleAuthenticationInfo(userBean, userBean.getPwd(), getName());
//4.返回身份处理对象
return simpleAuthenticationInfo;
}
}
流程总结
认证过程:
1、创建SecurityManager安全管理器
2、获取登录用户信息
3、根据用户名查询数据库得到用户实体,并通过SimpleAuthenticationInfo作身份处理再返回
4、调用框架内部方法进行比对验证
授权流程:
1、创建SecurityManager安全管理器
2、Subject主体带授权信息,请求到SecurityManager
3、SecurityManager调用Aythorizer授权
4、Authorizer结合主体一步步传递过来的授权信息,与realm中的数据比对,授权
整体请求流程
1、创建SecurityManager安全管理器
2、接收请求、根据请求路径先匹配匿名路径(anon),如果没有符合的就继续匹配权限拦截器链,,有就进行权限授权,如果没有,就再匹配身份认证路径,进行身份认证
3、返回请求结果成功或者失败
注意:
1、路径匹配(拦截器链)只能匹配单个,而且只能从最上面开始对比匹配,一旦匹配成功,就不再进入后续的拦截器中,即使后面的路径也能匹配
2、拦截器链设置顺序最先应该为匿名路径,即不需要身份认证的路径(比如登录、注册等等,不需要用户信息的请求路径);然后是权限请求拦截器、最后才是身份认证的拦截器