简介

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、拦截器链设置顺序最先应该为匿名路径,即不需要身份认证的路径(比如登录、注册等等,不需要用户信息的请求路径);然后是权限请求拦截器、最后才是身份认证的拦截器