权限与shiro框架

shiro(权限框架)

1.目前主流的权限框架
Spring security:重量级安全框架
Apache shiro:轻量级安全框架
2.Shiro的四大基石
① 身份认证:登录
② 授权:权限判断
③ 密码学:加密
④ 会话管理:session
3.从宏观上看
在这里插入图片描述
4.导包

<dependencies>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.4.0</version>
    </dependency>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
</dependencies>

4.案例一
1)准备配置文件shiro.ini
在这里插入图片描述
2) 代码

//读取带Shiro.ini文件并拿到工厂类
	Factory<SeeurityManager> factory = new IniSeeurityManagerFactory("classpath:shiro.ini")
	//从工厂类中获取SecurityManager 对象
	SecurityManager securityManager = factory.getInstance();
	//把SecurityManager 对象设置到上下文中
	/**
	*  把SecurityManager 对象放到一个地方没然后所有位置都能使用
	*/
    SecurityUtils.setSecurityManager(securityManager);
    //获取到当前用户(没有登录就是游客)
    Subject currentUser = SecurityUtils.getSubject();
    System.out.printn(currentUser.isAuthenticated());//判断用户是否登录
    if(!currectUser.isAuthenticated(){
    		try{
        		 UsernamePasswordToken token = new UsernamePasswordToken("root", "123456");
    	         currectUser.login(token);
      			 //设置记住我的功能
                 token.setRememberMe(true);
            } catch (UnknownAccountException uae) {
          			//未知账户异常
            } catch (IncorrectCredentialsException ice) {
             		//错误凭证异常
           } catch (AuthenticationException ae) {
              		//未知错误异常
            }	
	}

3) 常用方法
在这里插入图片描述5.自定义Realm(继承AuthorizingRealm类)

	/**
 * 自定义一个Realm
 */
public class MyRealm extends AuthorizingRealm {

    //获取到这个Realm的名称(随便取)
    @Override
    public String getName() {
        return "MyRealm";
    }
    //进行授权判断(权限)
    
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        	 //拿到认证的主要信息(用户名)
	        String username = (String) principalCollection.getPrimaryPrincipal();
	        //模拟根据用户名拿到角色信息与权限信息
	        Set<String> roles = getRolesByUsername(username);
	        Set<String> permissions = getPermissionsByUsername(username);
	        //拿到验证信息对象
	        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
	        //设置用户的角色
	        authorizationInfo.setRoles(roles);
	        //设置用户的权限
	        authorizationInfo.setStringPermissions(permissions);
	        return authorizationInfo;
    }
    //进行身份认证(登录)
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
           //获取用户令牌
	        UsernamePassowrdToken   token = (UsernamePassowrdToken)authenticationToken;
     		String username = token.getUsername(); //拿到用户名(注:这个用户名是传过来的)
	        //这里根据用户名去获取密码(如果没有获取到,相当于这个用户不存在,就返回null值)
	        String password = getByName(username);
	        if(password==null){
	        	//返回null,自动报UnknownAccountException 异常
	            return null;
	        }
	        //创建一个简单的身份信息(把用户名与密码放进去-注:它会自动的比较获取的密码与你传过来的密码)
	        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username,password,getName());
	        return authenticationInfo;
    }
    
    //模拟从数据库中获取信息
  private String getByName(String username) {
	        if("admin".equals(username)){
	            return "123456";
	        }else if("guest".equals(username)){
	            return "abcd";
	        }
	        return null;
}

测试

@Test
public void testMyRealm() throws Exception{

    //创建自己定义的Realm
    MyRealm myRealm = new MyRealm();
   //把Realm放到securityManager中去
    DefaultSecurityManager securityManager = new DefaultSecurityManager();
    securityManager.setRealm(myRealm);
    //把权限管理器放到相应的环境中(我们可以在项目任何位置拿到)
    SecurityUtils.setSecurityManager(securityManager);

    //拿到当前用户(Subject就是当前用户,游客)
    Subject currentUser = SecurityUtils.getSubject();
    //准备登录的令牌(准备用户名与密码)
    UsernamePasswordToken token = new UsernamePasswordToken("admin","123456");

    try {
        //根据令牌进行功能登录(当前用户进行登录)
        currentUser.login(token);
    } catch (UnknownAccountException e) {
        System.out.println("这个账号不存在!" + token.getPrincipal());
        e.printStackTrace();
    } catch (IncorrectCredentialsException ice) {
        System.out.println("这个密码不存在!" + token.getPrincipal());
        ice.printStackTrace();
    }catch (AuthenticationException e){
        System.out.println("i don't k");
    }

}

6.密码加密

SimpleHash simpleHash = new SimpleHash("MD5","admin","itsource",10);
System.out.println(simpleHash);

7.5.2.测试时让自定义Reaml加上算法

	 @Test
     public void testMyRealm() throws Exception{
         //创建自己定义的Realm
         MyRealm myRealm = new MyRealm();
        //把Realm放到securityManager中去
         DefaultSecurityManager securityManager = new DefaultSecurityManager();
         securityManager.setRealm(myRealm);
         //把权限管理器放到相应的环境中(我们可以在项目任何位置拿到)
         SecurityUtils.setSecurityManager(securityManager);
 

         //拿到当前用户(Subject就是当前用户,游客)
         Subject currentUser = SecurityUtils.getSubject();
         //准备登录的令牌(准备用户名与密码) -> 这里的密码进行了加密
         UsernamePasswordToken token = new UsernamePasswordToken("admin","123456");

         try {
             //根据令牌进行功能登录(当前用户进行登录)
             currentUser.login(token);
             System.out.println("登录成功啦。。。。");
         } catch (UnknownAccountException e) {
             System.out.println("这个账号不存在!" + token.getPrincipal());
             e.printStackTrace();
         } catch (IncorrectCredentialsException ice) {
             System.out.println("这个密码不存在!" + token.getPrincipal());
             ice.printStackTrace();
         }catch (AuthenticationException e){
             System.out.println("i don't k");
         }
     }

8.自定义Reaml加上盐值

@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    //明显的知道:这个authenticationToken就是UsernamePasswordtoken
    UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
    String username = token.getUsername(); //拿到用户名(注:这个用户名是传过来的)

    //这里根据用户名去获取密码(如果没有获取到,相当于这个用户不存在,就返回陪我)
    String password = getByName(username);
    if(password==null){
        return null;
    }
    //在这里加盐值需一个ByteSource对象,而Shiro提供了一个ByteSource对象给咱们
    ByteSource salt = ByteSource.Util.bytes("itsource");
    //创建一个简单的身份信息(把用户名与密码放进去-注:它会自动的比较获取的密码与你传过来的密码)
    SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username,password,salt,getName());
    return authenticationInfo;
}

private String getByName(String username) {
    if("admin".equals(username)){
        // 4a95737b032e98a50c056c41f2fa9ec6: 123456 迭代10次不加盐的结果
        // 831d092d59f6e305ebcfa77e05135eac: 123456 迭代10次加盐(itsource)的结果
        return "831d092d59f6e305ebcfa77e05135eac"; //修改为加密加盐后的数据
    }else if("guest".equals(username)){
        return "abcd";
    }
    return null;
}

Shiro集成Spring

把核心对象SecurityManager交由Spring创建
myRealm也交给Spring创建

1.导包

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

2.将拦截器拷贝到web.xml中(这个拦截器只过滤,处理要到Spring的拦截器中完成)

<!-- 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.配置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">

    <!-- 配置securityManager核心对象-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <!-- 配置一个realm,到数据库中获取权限数据 -->
        <property name="realm" ref="jpaRealm"/>
    </bean>

    <!-- 自定义一个realm-->
    <bean id="jpaRealm" class="cn.itsource.yxb.shiro.realm.JpaRealm">
			<property name="credentialsMatcher">
					<!—设置加密匹配方案-->
					 <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
							 <!-- 编码的方式使用:md5 -->
							 <property name="hashAlgorithmName" value="MD5"/>
						     <!-- 编码的次数:10 -->
							 <property name="hashIterations" value="10"/>
			     	</bean>
                </property>
	</bean>

    <!-- shiro的真实过滤器-->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <!-- 登录的url,如果没有登录,你访问的路径会跳到这个页面 -->
        <property name="loginUrl" value="/s/login.jsp"/>
        <!-- 登录成功的url,如果登录成功,会跳转到这个页面 -->
          
        <!-- 没有权限时跳转到这个位置 -->
        <property name="unauthorizedUrl" value="/s/unauthorized.jsp"/>
        <!--
            配置哪些资源被保护,哪些资源需要权限
            anon:不需要登录也可以访问相应的权限
            authc:需要权限才能访问
              /** :所有文件及其子文件
        -->
        <property name="filterChainDefinitions">
            <value>
                /s/login.jsp = anon
                /** = authc
            </value>
        </property>
    </bean>

</beans>

4.引入applicationContext-shiro.xml文件

在applicationContext.xml中添加

<import resource="applicationContext-shiro.xml"/>

5.因为如果在applicationContxt-shiro.xml配置权限拦截,因此可以配置

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <!-- 登录的url,如果没有登录,你访问的路径会跳到这个页面 -->
        <property name="loginUrl" value="/s/login.jsp"/>
        <!-- 登录成功的url,如果登录成功,会跳转到这个页面 -->
        <property name="successUrl" value="/s/main.jsp"/>
        <!-- 没有权限时跳转到这个位置 -->
        <property name="unauthorizedUrl" value="/s/unauthorized.jsp"/>

        <!-- 这个配置我们可以直接给一个map(动态的可以从代码中获取) -->
        <property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"></property>
    </bean>

    <!-- 这个bean是帮助咱们获取相应的值:它会到一个工厂bean中通过对应的方法拿到相应的值 -->
    <bean id="filterChainDefinitionMap" factory-bean="filterChainDefinitionMapBuilder" factory-method="createFilterChainDefinitionMap"></bean>
    <!-- 配置可以创建 -->
    <bean id="filterChainDefinitionMapBuilder" class="cn.itsource.yxb.shiro.realm.FilterChainDefinitionMapBuilder"></bean>
</beans>

6.创建一个FilterChainDefinitionMapBuilder 类

/**
 * 准备一个构造器类
 */
public class FilterChainDefinitionMapBuilder {
    public Map<String,String> createFilterChainDefinitionMap(){
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap();
        filterChainDefinitionMap.put("/s/login.jsp","anon");
        filterChainDefinitionMap.put("/login","anon");
        //这个值之后从数据库中查询到【用户-角色-权限-资源】
        filterChainDefinitionMap.put("/s/permission.jsp","perms[user:*]");
        filterChainDefinitionMap.put("//**","authc");
        return  filterChainDefinitionMap;
    }
}

7.一个简单的登录程序

@Controller
public class LoginController {
    @RequestMapping("/login")
    public String login(String username,String password){
        /**
         * 获取当前的 Subject. 调用 SecurityUtils.getSubject();
         * 测试当前的用户是否已经被认证. 即是否已经登录. 调用 Subject 的 isAuthenticated()
         * 若没有被认证, 则把用户名和密码封装为 UsernamePasswordToken 对象
         * 执行登录: 调用 Subject 的 login(AuthenticationToken) 方法.
         */
        //1.拿到访问的主体(当前登录用户)
        Subject subject = SecurityUtils.getSubject();
        //2.判断这个用户是否已经登录(通过验证)
        if(!subject.isAuthenticated()){
            //3.如果没有验证,就要完成登录
            UsernamePasswordToken token = new UsernamePasswordToken(username,password);
            try{
                //4.根据toke完成登录功能
                subject.login(token);
            }catch (UnknownAccountException e){
                System.out.println("用户名不存在!!");
                e.printStackTrace();
            }catch (IncorrectCredentialsException e){
                System.out.println("密码不存在!");
                e.printStackTrace();
            }catch (AuthenticationException e){
                System.out.println("登录出错!");
                e.printStackTrace();
            }

        }
        return "redirect:/s/main.jsp";
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值