shiro在SSM以及与Springboot+Mybatis中的实践

来源:互联网 发布:看广告赚钱软件 编辑:程序博客网 时间:2024/06/06 00:29
公司项目使用的是前后端分离的方式编写项目,并且我们后台项目打包是打包成jar,所以没有web.xml这个文件。公司是使用SpringBoot+Mybatis+Shiro的框架编写,使用Maven这个插件构建项目的。下面是我根据公司项目总结的如何使用java文件来配置Shiro环境的。参考文档如下:     SSM中shiro的实现:            http://blog.csdn.net/xiangwanpeng/article/details/54793768      多Realm的学习:               http://blog.csdn.net/u010837612/article/details/46053249  

1、在POM.xml中加入依赖

 1.1首先我们需要了解一下shiro常用jar包含义:           核心包shiro-core           Web相关包shiro-web           缓存包shiro-ehcache           与spring整合包shiro-spring           Ehcache缓存核心包ehcache-core           Shiro自身日志包slf4j-jdk141.2加入依赖
        <dependency>              <groupId>org.apache.shiro</groupId>              <artifactId>shiro-core</artifactId>              <version>1.4.0</version>          </dependency>         <!--这个里面就已经会有web这个jar包了-->       <dependency>           <groupId>org.apache.shiro</groupId>           <artifactId>shiro-spring</artifactId>           <version>1.4.0</version>       </dependency>       <dependency>           <groupId>org.apache.shiro</groupId>           <artifactId>shiro-ehcache</artifactId>           <version>1.4.0</version>       </dependency>

2、编写核心文件

首先我们需要了解一下Realm的含义:    shiro要进行身份验证,就要从realm中获取相应的身份信息来进行验证,简单来说,我们可以自行定义realm,    在realm中,从数据库获取身份信息,然后和 用户输入的身份信息进行匹配。这一切都由我们自己来定义。多Realm是由于多个不同的身份造成的2.1在有web.xml的情况下编写      2.1.1在web.xml中配置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>/*</url-pattern>    </filter-mapping>
      2.1.2编写自己的身份认证以及搜权(这个是通过继承AuthorizingRealm实现的)        是通过doGetAuthorizationInfo授予权限和AuthenticationToken登录身份验证两个方法实现的
@Componentpublic class MemberAccountRealm extends AuthorizingRealm {    @Autowired    private MemberAccountService memberAccountService;    /**     * 授权(验证权限时调用)     */    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {        // 获取登录时输入的用户名          MemberAccount memberAccount = (MemberAccount) principals.getPrimaryPrincipal();        String account = memberAccount.getAccount();        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();        // 用户角色授权        addRole(account, info);        // 用户权限授权        addPermisson(account, info);        return info;    }    /**     * 用户身份认证(登录时调用)     */    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws RuntimeException{        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)token;        // 获取前台用户输入的用户名和密码        String telephone = (String) token.getPrincipal();        // 查询用户信息        MemberAccount memberAccount=null;        try {            memberAccount = this.memberAccountService.queryMemberAccount(telephone, IsDelete.IS_NOT_DELETE);        } catch (Exception e) {            e.printStackTrace();            throw new RuntimeException(e);        }        // 获取密码并加密        String password = ShiroUtils.passwordEncrypr(String.valueOf(usernamePasswordToken.getPassword()), String.valueOf(memberAccount.getMemberId()));        // 重新放到token中        usernamePasswordToken.setPassword(password.toCharArray());        // 若存在,将此用户存放到登录认证中进行密码匹配        return new SimpleAuthenticationInfo(memberAccount,memberAccount.getPassword(), ByteSource.Util.bytes(telephone),getName());    }    /**     *      * 模拟授予权限     * @param loginName     * @param info     */    private void addPermisson(String loginName, SimpleAuthorizationInfo info) {        List<String> permissonList = new ArrayList<String>();        permissonList.add("sys:user:delete");        permissonList.add("sys:user:update");        permissonList.add("sys:user:save");        permissonList.add("sys:user:list");        //用户角色列表        Set<String> permissonSet = new HashSet<String>();             for ( String perm : permissonList ) {            if (StringUtils.isBlank(perm)) {                continue;            }            permissonSet.addAll(Arrays.asList(perm.trim().split(",")));        }        info.setStringPermissions(permissonSet);    }    /**     *      * 用户角色授权     * @param loginName     * @param info     */    private void addRole(String loginName, SimpleAuthorizationInfo info) {        List<String> RoleList = new ArrayList<String>();        RoleList.add("admin");        //用户角色列表        Set<String> RoleSet = new HashSet<String>();        for ( String role : RoleList ) {            if (StringUtils.isBlank(role)) {                continue;            }            RoleSet.addAll(Arrays.asList(role.trim().split(",")));        }        info.setRoles(RoleSet);    }}
      2.1.3可以自定义一个密码验证方法
public class CredentialsMatcher extends SimpleCredentialsMatcher{    @Override    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {        UsernamePasswordToken utoken = (UsernamePasswordToken) token;        // 获得用户输入的密码:(可以采用加盐(salt)的方式去检验)        String inPassword = new String(utoken.getPassword());        // 获得数据库中的密码        String dbPassword = (String) info.getCredentials();        // 进行密码的比对        return this.equals(inPassword, dbPassword);    }}
      2.1.4在src目录下家里ehcache.xml,文件内容如下:
<!--  ~ Hibernate, Relational Persistence for Idiomatic Java  ~  ~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.  ~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.  --><ehcache>    <!-- Sets the path to the directory where cache .data files are created.         If the path is a Java System Property it is replaced by         its value in the running VM.         The following properties are translated:         user.home - User's home directory         user.dir - User's current working directory         java.io.tmpdir - Default temp file path -->    <diskStore path="./target/tmp"/>    <!--Default Cache configuration. These will applied to caches programmatically created through        the CacheManager.        The following attributes are required for defaultCache:        maxInMemory       - Sets the maximum number of objects that will be created in memory        eternal           - Sets whether elements are eternal. If eternal,  timeouts are ignored and the element                            is never expired.        timeToIdleSeconds - Sets the time to idle for an element beforeQuery it expires. Is only used                            if the element is not eternal. Idle time is now - last accessed time        timeToLiveSeconds - Sets the time to live for an element beforeQuery it expires. Is only used                            if the element is not eternal. TTL is now - creation time        overflowToDisk    - Sets whether elements can overflow to disk when the in-memory cache                            has reached the maxInMemory limit.        -->    <defaultCache        maxElementsInMemory="10000"        eternal="false"        timeToIdleSeconds="120"        timeToLiveSeconds="120"        overflowToDisk="true"        />    <!--Predefined caches.  Add your cache configuration settings here.        If you do not have a configuration for your cache a WARNING will be issued when the        CacheManager starts        The following attributes are required for defaultCache:        name              - Sets the name of the cache. This is used to identify the cache. It must be unique.        maxInMemory       - Sets the maximum number of objects that will be created in memory        eternal           - Sets whether elements are eternal. If eternal,  timeouts are ignored and the element                            is never expired.        timeToIdleSeconds - Sets the time to idle for an element beforeQuery it expires. Is only used                            if the element is not eternal. Idle time is now - last accessed time        timeToLiveSeconds - Sets the time to live for an element beforeQuery it expires. Is only used                            if the element is not eternal. TTL is now - creation time        overflowToDisk    - Sets whether elements can overflow to disk when the in-memory cache                            has reached the maxInMemory limit.        -->    <!-- Sample cache named sampleCache1        This cache contains a maximum in memory of 10000 elements, and will expire        an element if it is idle for more than 5 minutes and lives for more than        10 minutes.        If there are more than 10000 elements it will overflow to the        disk cache, which in this configuration will go to wherever java.io.tmp is        defined on your system. On a standard Linux system this will be /tmp"        -->    <cache name="sampleCache1"        maxElementsInMemory="10000"        eternal="false"        timeToIdleSeconds="300"        timeToLiveSeconds="600"        overflowToDisk="true"        />    <!-- Sample cache named sampleCache2        This cache contains 1000 elements. Elements will always be held in memory.        They are not expired. -->    <cache name="sampleCache2"        maxElementsInMemory="1000"        eternal="true"        timeToIdleSeconds="0"        timeToLiveSeconds="0"        overflowToDisk="false"        /> -->    <!-- Place configuration for your caches following --></ehcache>
      2.1.5在spring的配置文件中加入以下代码:
     <!-- shiro start -->    <!-- 1. 配置SecurityManager -->    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">        <property name="cacheManager" ref="cacheManager" />        <!--这个是配置的多Realm的-->        <!--<property name="authenticator" ref="authenticator"></property>-->        <!-- 可以配置多个Realm,其实会把realms属性赋值给ModularRealmAuthenticator的realms属性 -->        <property name="realms">            <list>                <ref bean="authRealm" />            </list>        </property>    </bean>    <!-- 2. 配置CacheManager -->    <!-- 2.1 需要加入ehcache的jar包及配置文件 -->    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">        <property name="cacheManagerConfigFile" value="classpath:ehcache.xml" />    </bean>    <!-- 3. 配置Realm -->    <!-- 3.1 直接配置继承了org.apache.shiro.realm.AuthorizingRealm的bean -->    <bean id="authRealm" class="com.ysw.mes.common.shiro.MemberAccountRealm">        <!-- 配置密码匹配器 -->        <!-- 非自定义的写法        <property name="credentialsMatcher">            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">                <!-- 加密算法为MD5 -->                <property name="hashAlgorithmName" value="MD5"></property>                <!-- 加密次数 -->                <property name="hashIterations" value="1024"></property>            </bean>        </property>         -->         <!-- 自定义的写法 -->         <property name="credentialsMatcher" ref="credentialsMatcher">    </bean>    <!-- 自定义的密码匹配器 -->    <bean id="credentialsMatcher" class="com.ysw.mes.common.shiro.CredentialsMatcher"/>    <!-- 4. 配置LifecycleBeanPostProcessor,可以自定义地来调用配置在Spring IOC容器中shiro bean的生命周期方法 -->    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />    <!-- 5. 使能够在IOC容器中使用shiro的注解,但必须在配置了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>    <!-- 6. 配置ShiroFilter -->    <!-- 6.1 id必须和web.xml中配置的DelegatingFilterProxy的<filter-name>一致。 如果不一致,会抛出NoSuchBeanDefinitionException异常,因为shiro会在IOC容器中查找名称和<filter-name>         值一致的filter bean -->    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">        <property name="securityManager" ref="securityManager" />        <property name="loginUrl" value="/login.jsp" />        <!--<property name="successUrl" value="/home" />-->        <!-- 配置哪些页面需要受保护,以及访问这些页面需要的权限        <property name="filterChainDefinitions">            <value>                <!-- 第一次匹配优先的原则 -->                /jsp/login.jsp* = anon                /loginUser = anon                /logout* = anon                /jsp/error.jsp* = anon                /jsp/index.jsp* = authc                /* = authc                /*.* = authc            </value>        </property>         -->    </bean>    <!-- 7. 配置ModularRealmAuthenticator,可以实现多Realm认证 (公司项目并没有使用到)    <bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">        <!-- 配置认证策略,只要有一个Realm认证成功即可,并且返回所有认证成功信息 -->        <property name="authenticationStrategy">            <bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"></bean>        </property>    </bean>    -->    <!-- shiro end -->
2.2在无web.xml的情况下编写(在这里我就不配置cache了,相信大家会写的哈)    2.2.1编写同上的2.1.2、2.1.3    2.2.2编写一个Shiro的配置文件如下(相当于上面的 2.1.1和2.1.5的作用)
import java.util.LinkedHashMap;import org.apache.shiro.mgt.SecurityManager;import org.apache.shiro.spring.LifecycleBeanPostProcessor;import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;import org.apache.shiro.spring.web.ShiroFilterFactoryBean;import org.apache.shiro.web.mgt.DefaultWebSecurityManager;import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import com.ysw.mes.common.shiro.CredentialsMatcher;import com.ysw.mes.common.shiro.MemberAccountRealm;/** * 这个是shiro的配置文件 * 这个文件会使用到 *  CredentialsMatcher和MemberAccountRealm这两个文件 * @author admin *  *  * 学习shiro的网址有: *      http://blog.csdn.net/xiangwanpeng/article/details/54793768 *  *      其中对于多Realm的解释: *  * */@Configurationpublic class ShiroConfiguration {    /**     *      * @param manager     * @return     */    @Bean(name="shiroFilter")    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager) {        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();        bean.setSecurityManager(manager);        // 配置登录的url和登录成功的url        bean.setLoginUrl("/toLogin");//      bean.setSuccessUrl("/home");        // 配置访问权限        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();//        filterChainDefinitionMap.put("/jsp/login.jsp*", "anon"); //表示可以匿名访问//        filterChainDefinitionMap.put("/loginUser", "anon"); //        filterChainDefinitionMap.put("/logout*","anon");//        filterChainDefinitionMap.put("/jsp/error.jsp*","anon");//        filterChainDefinitionMap.put("/jsp/index.jsp*","authc");//        filterChainDefinitionMap.put("/*", "authc");//表示需要认证才可以访问//        filterChainDefinitionMap.put("/**", "authc");//表示需要认证才可以访问//        filterChainDefinitionMap.put("/*.*", "authc");        bean.setFilterChainDefinitionMap(filterChainDefinitionMap);        return bean;    }    //配置核心安全事务管理器    @Bean(name="securityManager")    public SecurityManager securityManager(@Qualifier("authRealm") MemberAccountRealm authRealm) {        System.err.println("--------------shiro已经加载----------------");        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();        manager.setRealm(authRealm);        return manager;    }    @    /**     * 配置自定义的权限以及身份认证器     * 以及将自定义的密码比较器注入进去     * @param matcher     * @return     */    @Bean(name="authRealm")    public MemberAccountRealm authRealm(@Qualifier("credentialsMatcher") CredentialsMatcher matcher) {        MemberAccountRealm authRealm=new MemberAccountRealm();        authRealm.setCredentialsMatcher(matcher);        return authRealm;    }    /**     * 使用的是自定义的密码比较器CredentialsMatcher     *      * @return CredentialsMatcher是自定义类     */    @Bean(name="credentialsMatcher")    public CredentialsMatcher credentialsMatcher() {        return new CredentialsMatcher();    }    /**     * 配置LifecycleBeanPostProcessor,可以自定义地来调用配置在Spring IOC容器中shiro bean的生命周期方法     * @return     */    @Bean    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){        return new LifecycleBeanPostProcessor();    }    /**     * 使能够在IOC容器中使用shiro的注解,但必须在配置了LifecycleBeanPostProcessor之后才可以使用     * @return     */    @Bean    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){        DefaultAdvisorAutoProxyCreator creator=new DefaultAdvisorAutoProxyCreator();        creator.setProxyTargetClass(true);        return creator;    }    @Bean    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager manager) {        AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor();        advisor.setSecurityManager(manager);        return advisor;    }}

在写完上面内容后,再看一次系统后,发现登录验证的顺序原来是这样的
1、由于在shiro的配置文件中配置了
这里写图片描述
这里写图片描述
2、首先访问/toLogin这个对应的方法
这里写图片描述
3、由于subject.login(token)这个,会调用到
这里写图片描述
4、将数据塞进token和info这两个实体之后进行比较
这里写图片描述

阅读全文
0 0
原创粉丝点击