shiro + ssm的开发步骤

shiro + ssm的开发步骤

前言

ssm的基本搭建就不多说了,主要讲shiro的基本配置。

pom配置

这次项目采用的是maven管理,所以首先在pom.xml中引入。

    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-all</artifactId>
      <version>1.2.3</version>
    </dependency>
    <dependency>
      <artifactId>ehcache-core</artifactId> 
      <groupId>net.sf.ehcache</groupId>
      <version>2.5.0</version>
    </dependency>

web.xml配置

web.xml中配置filter,有多个filter就放在最前面。
shiro中定义的filtername bean是要被wen.xml引用的,所以这里的filtername要和shiro中的filtername相同 。

    <!-- Shiro配置 -->
    <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>

ehcache配置

创建个xml,在里面复制上

<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false"  name="shirocache">
    <!--
   name:缓存名称。
   maxElementsInMemory:缓存最大个数。
   eternal:对象是否永久有效,一但设置了,timeout将不起作用。
   timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
   timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
   overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
   diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
   maxElementsOnDisk:硬盘最大缓存个数。
   diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
   diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
   memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
   clearOnFlush:内存数量最大时是否清除。
-->
    <diskStore path="F:\fileUpload\cache"/>
    <defaultCache
            maxElementsInMemory="10000"
            maxElementsOnDisk="0"
            eternal="true"
            overflowToDisk="true"
            diskPersistent="false"
            timeToIdleSeconds="0"
            timeToLiveSeconds="0"
            diskSpoolBufferSizeMB="50"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LFU"
    />
    <!-- 登录记录缓存 锁定10分钟 -->
    <cache name="passwordRetryCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
    <cache name="authorizationCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
    <cache name="authenticationCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
    <cache name="shiro-activeSessionCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
    <cache name="shiro_cache"
           maxElementsInMemory="2000"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="0"
           timeToLiveSeconds="0"
           maxElementsOnDisk="0"
           overflowToDisk="true"
           memoryStoreEvictionPolicy="FIFO"
           statistics="true">
    </cache>
</ehcache>

关于ehcache的属性介绍,可以看这篇博客Shiro + EHCache 缓存的使用

自定义的加密算法

public class CustomCredentialsMatcher extends SimpleCredentialsMatcher {

    //密码比较的方法   token代表用户在界面输入的用户名和密码     info代表从数据库中得到加密数据
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        //1.向下转型 
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;

        //2.将用户在界面输入的原始密码加密
        Object pwd = Encrypt.md5(new String(upToken.getPassword()), upToken.getUsername());

        //3.取出数据库中加密的密码
        Object dbPwd = info.getCredentials();

        return this.equals(pwd, dbPwd);
    }

UsernamePasswordTokenshiro中自己的类,是在执行登陆方法是调用的

            Subject subject = SecurityUtils.getSubject();
            //2.调用登录方法
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            subject.login(token);//当这一代码执行时,就会自动跳入到AuthRealm中认证方法

或者可以自己继承UsernamePasswordToken

public class ShiroToken extends UsernamePasswordToken implements Serializable{

    private static final long serialVersionUID = 1L;
    private String username;
    private String pwd;
    private String corpUid;    //业务的需求,
    ....

Encrypt为工具类,对密码加密

public class Encrypt {
    /*
     * 散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据,
     * 常见的散列算法如MD5、SHA等。一般进行散列时最好提供一个salt(盐),比如加密密码“admin”,
     * 产生的散列值是“21232f297a57a5a743894a0e4a801fc3”,
     * 可以到一些md5解密网站很容易的通过散列值得到密码“admin”,
     * 即如果直接对密码进行散列相对来说破解更容易,此时我们可以加一些只有系统知道的干扰数据,
     * 如用户名和ID(即盐);这样散列的对象是“密码+用户名+ID”,这样生成的散列值相对来说更难破解。
     */

    //高强度加密算法,不可逆
    public static String md5(String password, String salt){
        return new Md5Hash(password,salt,2).toString();
    }

}

自定义的Realm类

需要继承AuthorizingRealm实现接口

这里登陆认证,只根据用户名查询,因为我们自己写了一个加密算法,这里从token取到的密码还不是加密后,当它
返回时会跳转到我们写的CustomCredentialsMatcher 方法进行验证
在自定义Realm配置一定要开启缓存否会无效

public class SampleRealm extends AuthorizingRealm {

    @Autowired
    UUserService userService;
    @Autowired
    PermissionService permissionService;
    @Autowired
    RoleService roleService;

    public SampleRealm() {
        super();
    }
    /**
     *  认证信息,主要针对用户登录, 
     */
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken authcToken) throws AuthenticationException {

        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        //这里根据用户名查询用户是否存在
        User user = userService.queryForOne(token.getUsername());
        if(null == user){
            throw new AccountException("帐号或密码不正确!");
        /**
         * 如果用户的status为禁用。那么就抛出<code>DisabledAccountException</code>
         */
        }else if(UUser._0.equals(user.getStatus())){
            throw new DisabledAccountException("帐号已经禁止登录!");
        }else{
            //更新登录时间 last login time
            user.setLastLoginTime(new Date());
            userService.updateByPrimaryKeySelective(user);
        }
        return new SimpleAuthenticationInfo(user,user.getPswd(), getName());
    }

     /** 
     * 授权 
     */  
    @Override  
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {  

        User user = (User)SecurityUtils.getSubject().getPrincipal();
        SimpleAuthorizationInfo info =  new SimpleAuthorizationInfo();
        //根据用户ID查询角色(role),放入到Authorization里。
        Set<String> roles = roleService.findRoleByUserId(user.getUserId());
        info.setRoles(roles);
        //根据用户ID查询权限(permission),放入到Authorization里。
        Set<String> permissions = permissionService.findPermissionByUserId(user.getUserId());
        info.setStringPermissions(permissions);
        return info;  
    }  

spring-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"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">

    <description>Shiro的配置</description>

    <!-- SecurityManager配置 -->
    <!-- 配置Realm域 -->
    <!-- 密码比较器 -->
    <!-- 代理如何生成? 用工厂来生成Shiro的相关过滤器-->
    <!-- 配置缓存:ehcache缓存 -->
    <!-- 安全管理 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <!-- Single realm app.  If you have multiple realms, use the 'realms' property instead. -->
        <property name="realm" ref="authRealm"/><!-- 引用自定义的realm -->
        <!-- 缓存 -->
        <!--<property name="cacheManager" ref="shiroEhcacheManager"/>-->
    </bean>

    <!-- 自定义权限认证 -->
    <bean id="authRealm" class="club.thunderstorm.common.shiro.AuthRealm">
        <!-- 自定义密码加密算法  -->
        <property name="credentialsMatcher" ref="passwordMatcher"/>
        <!--缓存开启-->
        <property name="cachingEnabled" value="true" />
        <property name="authenticationCachingEnabled" value="true" />
        <property name="authenticationCacheName" value="authenticationCache" />
        <property name="authorizationCachingEnabled" value="true" />
        <property name="authorizationCacheName" value="authorizationCache" />
    </bean>

    <!-- 设置密码加密策略 md5hash -->
    <bean id="passwordMatcher" class="club.thunderstorm.common.shiro.CustomCredentialsMatcher"/>

    <!-- filter-name这个名字的值来自于web.xml中filter的名字 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <!--登录页面  -->
        <property name="loginUrl" value="/login"></property>
        <!-- 登录成功后 -->
        <!--<property name="successUrl" value="/home.action"></property>-->
        <property name="filterChainDefinitions">
            <!-- /**代表下面的多级目录也过滤 -->
            <value>
                /static/**=anon
                /login* = anon
                /** = authc
                /*.* = authc
            </value>
        </property>
    </bean>

    <!-- 用户授权/认证信息Cache, 采用EhCache  缓存 -->
    <bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/>
    </bean>

    <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    <!-- 生成代理,通过代理进行控制 -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor">
        <property name="proxyTargetClass" value="true"/>
    </bean>

    <!-- 安全管理器 -->
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>

</beans>

controller登陆方法

    //帐号密码封装到这个两个属性中
    public Map login(@RequestParam String email,@RequestParam String pwd){

        //调用shiro判断当前用户是否是系统用户
        Subject subject = SecurityUtils.getSubject();   //得到当前用户

        //shiro是将用户录入的登录名和密码(未加密)封装到token对象中
        UsernamePasswordToken token = new UsernamePasswordToken(email, pwd);
        try {
            //自动调用AuthRealm.doGetAuthenticationInfo
            subject.login(token);
            //登陆成功把用户放到session中,否则报异常
            User user =(User)subject.getPrincipal();
            subject.getSession().setAttribute("user",user);
        } catch (AuthenticationException e) {
            ....
        }
        ....

结束

最后还有一个很详细的shiro教程推荐Shiro 教程系列

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值