天天看点

shiro权限框架

shiro权限框架

1.shiro依赖包

<!-- shiro的支持包 -->
 <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-all</artifactId>
    <version>1.4.0</version>
    <type>pom</type>
</dependency>
  <!-- shiro与Spring的集成包 -->
  <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.0</version>
  </dependency>  
</dependencies>
           

2.在web.xml中配置shiro代理过滤器

<!-- Spring与shiro集成:需要定义一个shiro过滤器(这是一个代理过滤器,它会到spring的配置中找一个名称相同的真实过滤器) -->
<filter>
  <filter-name>shiroFilter</filter-name>
  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  <init-param>
    <param-name>targetFilterLifecycle</param-name>
    <param-value>true</param-value>
  </init-param>
</filter>

<filter-mapping>
  <filter-name>shiroFilter</filter-name>
  <url-pattern>\/*</url-pattern>
</filter-mapping>
           

3.spring配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--配置安全管理者-->
    <bean class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" id="securityManager">
        <!--配置安全管理者的权限数据-->
        <property name="realm" ref="myRealm"/>
    </bean>
    <bean class="com.wal.aisell.shiro.MyRealm" id="myRealm">
    //设置密码的匹配方式
        <property name="credentialsMatcher">
            <bean id="credentialsMatcher"  class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <!--设置加密方式-->
                <property name="hashAlgorithmName" value="MD5"/>
                <property name="hashIterations" value="10"/>
            </bean>
        </property>
    </bean>


    <!--配置shiro生命周期方法-->
    <bean class="org.apache.shiro.spring.LifecycleBeanPostProcessor" id="lifecycleBeanPostProcessor"/>
    <!--配置使用shiro的注解,但是必需配置在Spring Ioc容器中Shiro bean的生成周期方法-->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor"/>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>

    <!--配置真实的shiro过滤器 必须与web.xml中的代理过滤器名字一致-->
    <bean class="org.apache.shiro.spring.web.ShiroFilterFactoryBean" id="shiroFilter">
        <property name="securityManager" ref="securityManager"/>
        <!--登录时的url,如果没有登录会自动跳到该页面-->
        <property name="loginUrl" value="/login"/>
        <!--登录成功后跳到的页面-->
        <property name="successUrl" value="/main"/>
        <!--没有权限是跳到这个页面-->
        <property name="unauthorizedUrl" value="/s/unauthorized.jsp"/>


        <!--配置哪些资源被保护,哪些资源需要权限
            anon:不需要登录也可以访问相应的权限
            authc:需要权限才能访问
              ** :所有文件及其子文件
        -->
        <!--<property name="filterChainDefinitions">
            <value>
                /s/login.jsp=anon
                /login=anon
                /s/main.jsp=perms[user:*]
                \/**=authc
            </value>
        </property>-->
        <!--资源权限map-->
        <property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"/>
        <!--引入自定义权限过滤器-->
        <property name="filters">
            <map>
                <entry value-ref="myPermissionAuthorizationFilter" key="wal"></entry>
            </map>
        </property>
    </bean>
    <!--引入自定义权限过滤器bean-->
    <bean class="com.wal.aisell.shiro.MyPermissionAuthorizationFilter" id="myPermissionAuthorizationFilter"/>
     <!--在bean中设置哪些资源需要放行,哪些资源需要权限-->
    <bean class="com.wal.aisell.shiro.FilterChainDefinitionMapBuilder" id="filterChainDefinitionMapBuilder"></bean>
    <bean id="filterChainDefinitionMap" factory-bean="filterChainDefinitionMapBuilder"
          factory-method="creatFilterChainDefinitionMap"/>

</beans>
           

资源权限MapfilterChainDefinitionMapBuilder

public class FilterChainDefinitionMapBuilder {
    @Autowired
    private IPermissionService permissionService;
    public Map<String,String> creatFilterChainDefinitionMap(){
        LinkedHashMap<String, String> map = new LinkedHashMap<>();
       /* /s/login.jsp=anon
                /login=anon
                /s/main.jsp=perms[user:*]
        *//**=authc*/
        //静态资源放行
        map.put("/login","anon");
        map.put("*.js","anon");
        map.put("*.css","anon");
        map.put("/css/**","anon");
        map.put("/js/**","anon");
        map.put("/easyui/**","anon");
        map.put("/images/**","anon");
        //从数据库中读出访问路径所需要的权限
        List<Permission> permissionList = permissionService.findAll();
        permissionList.forEach(permission -> {
            String url = permission.getUrl();
            String sn = permission.getSn();
            //这里要改成自定义的权限过滤器对应的key值
            map.put(url, "wal["+sn+"]");
        });
            map.put("//**","authc" );
        return map;
    }
}
           

自定义权限过滤器 根据用户权限做相应处理

//复写默认权限过滤器,使其支持ajax请求
public class MyPermissionAuthorizationFilter extends PermissionsAuthorizationFilter {
    //这是请求没有权限时处理的方法,默认是跳转页面,现在要加一个对ajax的处理
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
        Subject subject = this.getSubject(request, response);
        if (subject.getPrincipal() == null) {
            this.saveRequestAndRedirectToLogin(request, response);
        } else {
            //先强转成http请求,因为http请求才能获得请求头
            HttpServletRequest req = (HttpServletRequest)request;
            HttpServletResponse resp = (HttpServletResponse)response;
            String header = req.getHeader("X-Requested-With");
            //ajax请求的标志XMLHttpRequest
            if (header != null && "XMLHttpRequest".equals(header)){
                //设置响应类型
                resp.setContentType("text/json,charset=UTF-8");
                //设置响应消息
                resp.getWriter().print("{\"seccess\":false,\"msg\":\"没有权限\"}");
            }else {
                String unauthorizedUrl = this.getUnauthorizedUrl();
                if (StringUtils.hasText(unauthorizedUrl)) {
                    WebUtils.issueRedirect(request, response, unauthorizedUrl);
                } else {
                    WebUtils.toHttp(response).sendError(401);
                }
            }
        }

        return false;
    }
}
           

自定义MyRealm 用户身份认证和权限管理

public class MyRealm extends AuthorizingRealm {
    //验证角色和权限
    @Autowired
    private IPermissionService permissionService;
    @Autowired
    private IRoleService roleService;
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //拿到身份验证成功后返回的主题
        Employee employee = (Employee)principalCollection.getPrimaryPrincipal();
        //更具登录用户得到该用户的角色信息
        Set<Role> roles = roleService.findRolesByLoginUser(employee);

        Set<String> rolesStr = new HashSet<>();
        Set<String> permissionAll = new HashSet<>();
        roles.forEach(role -> {
            //根据登录用户的角色信息,拿到用户权限
            Set<String> permission = permissionService.findPermissionByRole(role);
            permissionAll.addAll(permission);
            String sn = role.getSn();
            rolesStr.add(sn);

        });
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setStringPermissions(permissionAll);
        authorizationInfo.setRoles(rolesStr);
        //Set<String> permission = permissionService.findPermissionByLoginUser(employee);
        //SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //authorizationInfo.setStringPermissions(permission);
        return authorizationInfo;
    }
    //验证身份
    @Autowired
    private IEmployeeService employeeService;
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //authenticationToken对应subject.login(token) 中的token
        String username = (String)authenticationToken.getPrincipal();
        String password = employeeService.findPasswordByusername(username);
        Employee employee = employeeService.findByusername(username);
        if (password==null){
            return null;
        }
        //设置盐值
        ByteSource salt = ByteSource.Util.bytes(MD5Utils.SALT);
        //密码匹配成功后 ,subject.getPrincipal获得的就是employee,如果你写的是usernamesubject获得的就是username
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(employee, password,salt, getName());
        return authenticationInfo ;
    }