云悦智销项目05_shiro权限

1,Shiro
Java安全轻量级权限框架
shiro(轻量级,粗粒度) , Spring security(细粒度)
RBAC:权限(登录,授权) 用户(n)-角色(n)-权限(n)(资源)
shiro的四大基石
身份验证(登录) Authenticatio
授权(权限)Authorization
密码学 Cryptography
会话管理Session Managerment(支持所有)

重要的对象
subject,当前用户
shiro SecurityManager ,所有权限管理
realm 获取权限资料,角色

2,自定义Realm
准备自定义Realm
写一个Realm,继承AuthorizingRealm
提供了两个方法,一个是授权doGetAuthorizationInfo,一个是身份认证 doGetAuthenticationInfo

public class MyRealm extends AuthorizingRealm {

    //授权认证功能就写在这里面
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //从数据库中获取角色并放且放到授权对象中
        Set<String> roles = getRoles();
        authorizationInfo.setRoles(roles);
        //从数据库中获取权限并放且放到授权对象中
        Set<String> perms = getPerms();
        authorizationInfo.setStringPermissions(perms);
        return authorizationInfo;
    }

    /**
     * 假设这里获取到当前用户的角色
     */
    private Set<String> getRoles(){
        Set<String> roles = new HashSet<>();
        roles.add("admin");
        roles.add("it");
        return roles;
    }
    /**
     * 假设这里获取到当前用户的权限
     */
    private Set<String> getPerms(){
        Set<String> perms = new HashSet<>();
        perms.add("employee:index");
        return perms;
    }

    /**
     * 记住:如果这个方法返回null,就代表是用户名错误,shiro就会抛出:UnknownAccountException
     */
    //身份认证(登录)就写在这里面
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //1.拿到令牌(UsernamePasswordToken)
        UsernamePasswordToken token =  (UsernamePasswordToken)authenticationToken;
        //2.拿到用户名,判断这个用户是否存在
        // 2.1 拿到传过来的用户名
        String username = token.getUsername();
        // 2.2 根据用户名从数据库中拿到密码(以后会拿用户对象)
        String password = this.getUsers(username);
        // 2.3 如果没有拿到密码(没有通过用户名拿到相应的用户->用户不存在)
        if(password==null){
            return null;
        }

        //记住:我们只在正常完成这里的功能,shiro会判断密码是否正确
        //3.返回 AuthenticationInfo这个对象
        /**
         * 咱们创建对象需要传的参数:
         * Object principal:主体(可以乱写) -> 登录成功后,你想把哪一个对象存下来
         * Object credentials:凭证(就是密码) -> 数据库中的密码
         * credentials(密码)Salt:盐值
         * String realmName : realm的名称(可以乱写)
         */
        //拿到咱们的盐值对象(ByteSource)
        ByteSource salt = ByteSource.Util.bytes("itsource");
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username,password,salt,"myRealm");
        return authenticationInfo;
    }

    /**
     * 假设这里是根据用户名进行的查询
     *  MD5:e10adc3949ba59abbe56e057f20f883e
     *  MD5+10次:4a95737b032e98a50c056c41f2fa9ec6
     *  MD5+10次+itsource:831d092d59f6e305ebcfa77e05135eac
     */
    public String getUsers(String username){
        if("admin".equals(username)){
            return "831d092d59f6e305ebcfa77e05135eac";
        }else if("zhang".equals(username)){
            return "123";
        }
        return null;
    }
}

测试自定义Realm

 @Test
    public void testMyRealm() throws Exception{
        //一.创建一个SecurityManager对象
        // 1.创建realm对象
        MyRealm myRealm = new MyRealm();
        // 2.创建SecurityManager对象
        DefaultSecurityManager securityManager = new DefaultSecurityManager(myRealm);
        //②.相当于把SecurityManager放到了当前上下文
        SecurityUtils.setSecurityManager(securityManager);
        //③.拿到当前用户
        Subject subject = SecurityUtils.getSubject();

        //Hashed(哈希)Credentials(认证)Matcher(匹配器)
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        //设置哈希算法
        matcher.setHashAlgorithmName("MD5");
        //设置迭代次数
        matcher.setHashIterations(10);
        //把匹配器交给shiro
        myRealm.setCredentialsMatcher(matcher);

        System.out.println("用户是否登录:"+subject.isAuthenticated());
        //④.如果没有登录,让他登录
        if(!subject.isAuthenticated()){
            try {
                UsernamePasswordToken token = new UsernamePasswordToken("admin","123456");
                subject.login(token);
            } catch (UnknownAccountException e) {
                e.printStackTrace();
                System.out.println("用户名错误");
            } catch (IncorrectCredentialsException e) {
                e.printStackTrace();
                System.out.println("密码错误");
            } catch (AuthenticationException e) {
                e.printStackTrace();
                System.out.println("神迷错误");
            }
        }
        System.out.println("用户是否登录:"+subject.isAuthenticated());

        System.out.println("是否是admin角色:"+subject.hasRole("admin"));
        System.out.println("是否是hr角色:"+subject.hasRole("hr"));

        System.out.println("是否有employee:index权限:"+subject.isPermitted("employee:index"));
        System.out.println("是否有employee:save权限:"+subject.isPermitted("employee:save"));
        System.out.println("是否有department:index权限:"+subject.isPermitted("department:index"));


    }

3,集成spring
需要有Spring的环境 ssj/项目
导包

<!-- 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>

web.xml中配置代理过滤器
<!-- shiro的过滤器(帮我们拦截请求)-》什么事情都不做
Delegating:();(工作、权力等)委托(给下级); 选派(某人做某事)
Proxy:代理 -> 需要通过名称(shiroFilter)去找真正的过滤器
-->
<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>/*

准备自定义Realm

public class JpaRealm extends AuthorizingRealm {


    //授权认证功能就写在这里面
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //从数据库中获取角色并放且放到授权对象中
        Set<String> roles = getRoles();
        authorizationInfo.setRoles(roles);
        //从数据库中获取权限并放且放到授权对象中
        Set<String> perms = getPerms();
        authorizationInfo.setStringPermissions(perms);
        return authorizationInfo;
    }

    /**
     * 假设这里获取到当前用户的角色
     */
    private Set<String> getRoles(){
        Set<String> roles = new HashSet<>();
        roles.add("admin");
        roles.add("it");
        return roles;
    }
    /**
     * 假设这里获取到当前用户的权限
     */
    private Set<String> getPerms(){
        Set<String> perms = new HashSet<>();
        perms.add("employee:index");
//        perms.add("user:*");
        return perms;
    }

    /**
     * 记住:如果这个方法返回null,就代表是用户名错误,shiro就会抛出:UnknownAccountException
     */
    //身份认证(登录)就写在这里面
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //1.拿到令牌(UsernamePasswordToken)
        UsernamePasswordToken token =  (UsernamePasswordToken)authenticationToken;
        //2.拿到用户名,判断这个用户是否存在
        // 2.1 拿到传过来的用户名
        String username = token.getUsername();
        // 2.2 根据用户名从数据库中拿到密码(以后会拿用户对象)
        String password = this.getUsers(username);
        // 2.3 如果没有拿到密码(没有通过用户名拿到相应的用户->用户不存在)
        if(password==null){
            return null;
        }

        //记住:我们只在正常完成这里的功能,shiro会判断密码是否正确
        //3.返回 AuthenticationInfo这个对象
        /**
         * 咱们创建对象需要传的参数:
         * Object principal:主体(可以乱写) -> 登录成功后,你想把哪一个对象存下来
         * Object credentials:凭证(就是密码) -> 数据库中的密码
         * credentials(密码)Salt:盐值
         * String realmName : realm的名称(可以乱写)
         */
        //拿到咱们的盐值对象(ByteSource)
        ByteSource salt = ByteSource.Util.bytes("itsource");
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username,password,salt,"myRealm");
        return authenticationInfo;
    }

    /**
     * 假设这里是根据用户名进行的查询
     *  MD5:e10adc3949ba59abbe56e057f20f883e
     *  MD5+10次:4a95737b032e98a50c056c41f2fa9ec6
     *  MD5+10次+itsource:831d092d59f6e305ebcfa77e05135eac
     */
    public String getUsers(String username){
        if("admin".equals(username)){
            return "831d092d59f6e305ebcfa77e05135eac";
        }else if("zhang".equals(username)){
            return "123";
        }
        return null;
    }
}


准备工厂返回权限
返回的Map值是有顺序的
修改后要重启(热启动无效)
/**
 * 用于返回下面的这些值(**这里的值是有顺序的:LinkedHashMap)**
 *   
         /login = anon
         /s/permission.jsp = perms[user:index]
         /** = authc
    
    这里修改后要重新启动tomcat
 */
public class ShiroFilterMapFactory {

    public Map<String,String> createMap(){
        Map<String,String> map = new LinkedHashMap<>();
        //anon:需要放行的路径
        map.put("/login","anon");
        //perms:权限拦截
        map.put("/s/permission.jsp","perms[employee:index]");
        //authc:拦截
        map.put("/**","authc");
        return map;
    }
}

applicationContext-shiro.xml的配置

先在 applicationContext.xml 中引入它 <import resource="classpath:applicationContext-shiro.xml" />
<?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-3.0.xsd">


    <!--
        Shiro的核心对象(权限管理器)
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(jpaRealm)
    -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="jpaRealm"/>
    </bean>

    <!--
        JpaRealm jpaRealm = new JpaRealm();
        配置咱们的自定义realm
     -->
    <bean id="jpaRealm" class="cn.itsource.aisell.web.shiro.JpaRealm">
        <!--Realm的名称-->
        <property name="name" value="jpaRealm"/>
        <property name="credentialsMatcher">
            <!-- 配置哈希密码匹配器 -->
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <!--加密方式:MD5-->
                <property name="hashAlgorithmName" value="MD5"/>
                <!--迭代次数-->
                <property name="hashIterations" value="10" />
            </bean>
        </property>
    </bean>

    <!-- 这三个配置好,可以支持注解权限 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
    <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真正的过滤器(功能就是它完成的)
            这个bean的名称必需和web.xml里的的代理过滤器名字相同
     -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!--必需要用到权限管理器-->
        <property name="securityManager" ref="securityManager"/>
        <!--如果你没有登录,你会进入这个页面-->
        <property name="loginUrl" value="/s/login.jsp"/>
        <!--登录成功后,进入的页面(一般没什么用)-->
        <property name="successUrl" value="/s/main.jsp"/>
        <!--如果你没有权限,你会进入这个页面-->
        <property name="unauthorizedUrl" value="/s/unauthorized.jsp"/>
        <!-- 过滤描述
            anon:不需要登录也可以访问
            authc:登录与权限的拦截
            perms:如果你有user:index的权限,你就可以访问:/s/permission.jsp
        -->
        <!--
        <property name="filterChainDefinitions">
            <value>
                /login = anon
                /s/permission.jsp = perms[user:index]
                /** = authc
            
        
        -->
        
    

    
    
    
    
    

你可能感兴趣的:(项目搭建)