Spring集成Shiro


欢迎访问我的网站:www.ifueen.com

Spring集成Shiro

Shiro入门

关于Shiro的介绍网上很多资料,我这里就不再强调了

权限分类

权限一般分为登录权限和操作授权两部分

Shiro的四个组成部分:用户-角色-权限-资源

使用Shiro

创建好项目,然后在pom.xml文件中加入依赖

<!-- shiro核心jar包 -->
    <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>

准备ini文件

文件中有角色权限等

# -----------------------------------------------------------------------------
# Users and their assigned roles
#
# Each line conforms to the format defined in the
# org.apache.shiro.realm.text.TextConfigurationRealm#setUserDefinitions JavaDoc
# -----------------------------------------------------------------------------

[users]
root = 123456, admin
guest = guest, guest

[roles]
# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *
guest = department:*
schwartz = lightsaber:*
goodguy = winnebago:drive:eagle5

测试基本功能

package com.ifueen.shiro;

import org.apache.shiro.mgt.SecurityManager;

public class HelloShiro {

    @Test
    public void testShiroHello(){
        //拿到核心对象并且读取ini文件
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();
        //拿到上下文对象
        SecurityUtils.setSecurityManager(securityManager);
        //拿到当前的用户
        Subject currentUser  = SecurityUtils.getSubject();
        //判断是否登录
        System.out.println("是否登录:"+currentUser.isAuthenticated());
        //获取到登录令牌
        UsernamePasswordToken token = new UsernamePasswordToken("guest", "guest");
        //登录
        try {
            currentUser.login(token);
        } catch (AuthenticationException e) {
            System.out.println("用户名错误,建议看脑科");
        }
        System.out.println("是否登录:"+currentUser.isAuthenticated());
        System.out.println("是否是admin角色:"+currentUser.hasRole("admin"));
        System.out.println("是否能够操作employee:"+currentUser.isPermitted("employee:*"));
        //退出
        currentUser.logout();
        System.out.println("是否登录:"+currentUser.isAuthenticated());
        
    }

}

自定义Realm

package com.ifueen.shiro;

import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import java.util.HashSet;
import java.util.Set;

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

    //授权功能
    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;
    }

    /**
     * 假设这里是角色管理
     * @return
     */
    public Set<String> getRoles(){
        Set<String> set = new HashSet<String>();
        set.add("admin");
        set.add("HR");
        return set;
    }

    /**
     * 假设这里是权限管理
     * @return
     */
    public Set<String> getPerms(){
        Set<String> set = new HashSet<String>();
        set.add("*");
        return set;
    }


    //身份认证功能
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //拿到令牌
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        //通过令牌拿到用户名
        String username = token.getUsername();
        //通过用户名查找到密码
        String password = getUser(username);
        //如果密码不存在(表示没有通过用户名查找到用户,用户不存在的情况)
        if (password==null){
            return null;
        }
        /**
         * 返回的SimpleAuthenticationInfo对象
         * 第一个参数表示主体:随便填写
         * 第二个参数表示密码:填写数据库中的密码
         * 第三个参数:盐值
         * 第四个参数表示这个Realm的名称:自定义名字
         */
        //对于加密后的密码,这里不需要进行加密,shiro会自动判断密码是否正确,这里只需要写正常功能即可
        //拿到盐值对象
        ByteSource salt = ByteSource.Util.bytes("ifueen");
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username, password, salt,"myRealm");

        return authenticationInfo;
    }

    /**
     * 这里模拟一个返回密码的方法
     * @param username
     * @return
     */
    public String getUser(String username){
        if ("admin".equals(username)){
            return "06a49f27623237c3ca826ca617661285";
        }else if ("come".equals(username)){
            return "45565";
        }
        return null;
    }

}

测试自定义Realm

/**
 * 测试MyRealm
 */
public class MyRealmTest {

    @Test
    public void testMyRealm(){
        //创建MyRealm对象
        MyRealm myRealm = new MyRealm();
        //通过Realm对象拿到SecurityManager对象
        DefaultSecurityManager securityManager = new DefaultSecurityManager(myRealm);
        //将securityManager设置到上下文中
        SecurityUtils.setSecurityManager(securityManager);
        //拿到当前用户
        Subject subject = SecurityUtils.getSubject();
        //设置Hash算法
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("MD5");
        matcher.setHashIterations(10);
        //把匹配其交给shiro
        myRealm.setCredentialsMatcher(matcher);

        System.out.println("是否登录:"+subject.isAuthenticated());
        //没有登录就让它登录
        if (!subject.isAuthenticated()){
            //拿到令牌
            UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");
            try {
                subject.login(token);
            } catch (UnknownAccountException e) {
                System.out.println("账户不存在啊大哥");
            } catch (IncorrectCredentialsException e) {
                System.out.println("密码错误,建议自杀");
            } catch (AuthenticationException e) {
                System.out.println("发生了未知错误");
            }
        }
        System.out.println("用户是否登录:"+subject.isAuthenticated());
        System.out.println("用户是否为admin角色:"+subject.hasRole("admin"));
        System.out.println("用户是否能够操作employee:"+subject.isPermitted("employee:save"));
    }

    /**
     * 测试MD5加密
     *
     */
    @Test
    public void testHash(){
        /**
         * 参数一:加密的算法
         * 参数二:原密码
         * 参数三:盐值(就是随便加点东西在后边)
         * 参数四:加密次数
         */
        SimpleHash hash = new SimpleHash("MD5", "123456", "ifueen", 10);
        System.out.println(hash.toString());
    }

}

Spring集成shiro

导入shiro的支持包

在pom.xml中加入

<!-- 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的过滤器(虚假的过滤器)
  它不会只负责拦截,之后不做任何操作
    Proxy:代理 -> 需要通过名称去找真正的过滤器
  -->
  <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>

准备好自定义的Realm

直接将刚刚创建的自定义Realm拷贝过来

package com.ifueen.shiro;

import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import java.util.HashSet;
import java.util.Set;

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

    //授权功能
    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;
    }

    /**
     * 假设这里是角色管理
     * @return
     */
    public Set<String> getRoles(){
        Set<String> set = new HashSet<String>();
        set.add("admin");
        set.add("HR");
        return set;
    }

    /**
     * 假设这里是权限管理
     * @return
     */
    public Set<String> getPerms(){
        Set<String> set = new HashSet<String>();
        set.add("*");
        return set;
    }


    //身份认证功能
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //拿到令牌
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        //通过令牌拿到用户名
        String username = token.getUsername();
        //通过用户名查找到密码
        String password = getUser(username);
        //如果密码不存在(表示没有通过用户名查找到用户,用户不存在的情况)
        if (password==null){
            return null;
        }
        /**
         * 返回的SimpleAuthenticationInfo对象
         * 第一个参数表示主体:随便填写
         * 第二个参数表示密码:填写数据库中的密码
         * 第三个参数:盐值
         * 第四个参数表示这个Realm的名称:自定义名字
         */
        //对于加密后的密码,这里不需要进行加密,shiro会自动判断密码是否正确,这里只需要写正常功能即可
        //拿到盐值对象
        ByteSource salt = ByteSource.Util.bytes("ifueen");
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username, password, salt,"myRealm");

        return authenticationInfo;
    }

    /**
     * 这里模拟一个返回密码的方法
     * @param username
     * @return
     */
    public String getUser(String username){
        if ("admin".equals(username)){
            return "06a49f27623237c3ca826ca617661285";
        }else if ("come".equals(username)){
            return "45565";
        }
        return null;
    }

}

准备一个存放权限的工厂

注意:修改了这里的数据后热启动无效,需要重新部署

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;
    }
}

配置SpringContext-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的核心文件(权限管理器) -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="jpaRealm"/>
    </bean>



    <!-- 配置自己写的JpaRealm -->
    <bean id="jpaRealm" class="com.ifueen.aishell.web.shiro.JpaRealm">
        <property name="name" value="jpaRealm"/>
        <property name="credentialsMatcher">
            <!-- 配置Hash密码匹配器-->
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <!-- 设置加密方式 -->
                <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>



    <!--
     真正的过滤器
     名称必须和web.xml里面的过滤器名称一样
     -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- 权限管理器 -->
        <property name="securityManager" ref="securityManager"/>
        <!-- 登录之前的页面 -->
        <property name="loginUrl" value="/login"/>
        <!-- 登录成功后访问的页面(一般用不到)-->
        <property name="successUrl" value="/main"/>
        <!-- 没有权限时跳转的页面 -->
        <property name="unauthorizedUrl" value="/s/unauthorized.jsp"/>
        <!--
        <property name="filterChainDefinitions">
            <value>
                /login = anon
                /s/permission.jsp = perms[user:index]
                /** = authc
            </value>
        </property>
        -->
        <!-- 配置权限 -->
        <property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"/>
    </bean>
    
    <bean name="filterChainDefinitionMap" factory-bean="shiroFilterMapFactory" factory-method="createMap"/>
    <bean name="shiroFilterMapFactory" class="com.ifueen.aishell.web.shiro.ShiroFilterMapFactory"/>

</beans>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值