在ssm项目中引入shiro

概述:Shiro是apache旗下一个开源框架,它将软件系统的安全认证相关的功能抽取出来,实现用户身份认证,权限授权、加密、会话管理等功能,组成了一个通用的安全认证框架。

1.在pom.xml文件加入shiro的相关jar包:

<dependency>

         <groupId>org.apache.shiro</groupId>

         <artifactId>shiro-core</artifactId>

         <version>1.2.3</version>

      </dependency>

      <dependency>

         <groupId>org.apache.shiro</groupId>

         <artifactId>shiro-web</artifactId>

         <version>1.2.3</version>

      </dependency>

      <dependency>

         <groupId>org.apache.shiro</groupId>

         <artifactId>shiro-spring</artifactId>

         <version>1.2.3</version>

      </dependency>

      <dependency>

         <groupId>org.apache.shiro</groupId>

         <artifactId>shiro-ehcache</artifactId>

         <version>1.2.3</version>

      </dependency>

      <dependency>

         <groupId>org.apache.shiro</groupId>

         <artifactId>shiro-quartz</artifactId>

         <version>1.2.3</version>

      </dependency>

2.在web.xml加入shiro的配置

<!-- 配置  Shiro 的 Filter -->
<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.在springmvc.xml文件加入shiro的注解开发配置(可选项,若不采用注解开发,可以不配置)

<!-- 使 Shiro 的注解起作用, Shiro 的注解标示在方法上. 例如 @RequiresRoles、@RequiresPermissions -->
<!-- 因为目前是在 Handler 的方法上添加注解, 所以以下的配置需要作用在 SpringMVC 的 IOC 容器中. 而不是其父容器中.  -->
<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>

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


<!-- 配置緩存管理器 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<!-- 指定 ehcache 的配置文件 -->
        <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/>
    </bean>


<!-- 配置进行授权和认证的 Realm -->
<bean id="myRealm"
class="cn.ljj.realm.MyRealm"
init-method="setCredentialMatcher"></bean>


<!-- 配置 Shiro 的 SecurityManager Bean. -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="cacheManager" ref="cacheManager"/>
        <property name="realm" ref="myRealm"/>

        <!-- 记住我 -->
<property name="rememberMeManager" ref="rememberMeManager"/>
    </bean>
    <!-- rememberMeManager管理器,写cookie,取出cookie生成用户信息 -->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<property name="cookie" ref="rememberMeCookie" />
</bean>


<!-- 记住我cookie -->
<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<!-- rememberMe是cookie的名字 -->
<constructor-arg value="rememberMe" />
<!-- 记住我cookie生效时间30天 -->
<property name="maxAge" value="2592000" />
</bean>


    <!-- 配置 Bean 后置处理器: 会自动的调用和 Spring 整合后各个组件的生命周期方法. -->
<bean id="lifecycleBeanPostProcessor" 
class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>


    <!-- 配置 ShiroFilter bean: 该 bean 的 id 必须和 web.xml 文件中配置的 shiro filter 的 name 一致  -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <!-- 装配 securityManager -->
        <property name="securityManager" ref="securityManager"/>
        <!-- 配置登陆页面 -->
        <property name="loginUrl" value="/shiro-login"/>   //登入验证的action路径
        <!-- 登陆成功后的一面 -->
        <property name="successUrl" value="/shiro-success.jsp"/>
        <property name="unauthorizedUrl" value="/shiro-unauthorized.jsp"/>
<!-- 具体配置需要拦截哪些 URL, 以及访问对应的 URL 时使用 Shiro 的什么 Filter 进行拦截.  -->
        <property name="filterChainDefinitions">
            <value>
            <!-- 配置登出: 使用 logout 过滤器 -->
                /shiro-logout = logout
                /shiro-* = anon
                /user.jsp = roles[user]
                /admin.jsp = roles[admin]

                <!--商品查询需要商品查询权限 ,取消url拦截配置,使用注解授权方式 -->
<!-- /items/queryItems.action = perms[item:query]
/items/editItems.action = perms[item:edit] -->
<!-- 配置记住我或认证通过可以访问的地址 -->
/index.jsp  = user
/first.action = user
        /welcome.jsp = user
                /** = authc
            </value>
        </property>

    </bean>

</beans>

5.配置ehcache-shiro.xml

<!--
  ~ Licensed to the Apache Software Foundation (ASF) under one
  ~ or more contributor license agreements.  See the NOTICE file
  ~ distributed with this work for additional information
  ~ regarding copyright ownership.  The ASF licenses this file
  ~ to you under the Apache License, Version 2.0 (the
  ~ "License"); you may not use this file except in compliance
  ~ with the License.  You may obtain a copy of the License at
  ~
  ~     http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing,
  ~ software distributed under the License is distributed on an
  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  ~ KIND, either express or implied.  See the License for the
  ~ specific language governing permissions and limitations
  ~ under the License.
  -->


<!-- EhCache XML configuration file used for Shiro spring sample application -->
<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="java.io.tmpdir/shiro-spring-sample"/>




    <!--Default Cache configuration. These will applied to caches programmatically created through
    the CacheManager.


    The following attributes are required:


    maxElementsInMemory            - 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.
    overflowToDisk                 - Sets whether elements can overflow to disk when the in-memory cache
                                     has reached the maxInMemory limit.


    The following attributes are optional:
    timeToIdleSeconds              - Sets the time to idle for an element before it expires.
                                     i.e. The maximum amount of time between accesses before an element expires
                                     Is only used if the element is not eternal.
                                     Optional attribute. A value of 0 means that an Element can idle for infinity.
                                     The default value is 0.
    timeToLiveSeconds              - Sets the time to live for an element before it expires.
                                     i.e. The maximum time between creation time and when an element expires.
                                     Is only used if the element is not eternal.
                                     Optional attribute. A value of 0 means that and Element can live for infinity.
                                     The default value is 0.
    diskPersistent                 - Whether the disk store persists between restarts of the Virtual Machine.
                                     The default value is false.
    diskExpiryThreadIntervalSeconds- The number of seconds between runs of the disk expiry thread. The default value
                                     is 120 seconds.
    memoryStoreEvictionPolicy      - Policy would be enforced upon reaching the maxElementsInMemory limit. Default
                                     policy is Least Recently Used (specified as LRU). Other policies available -
                                     First In First Out (specified as FIFO) and Less Frequently Used
                                     (specified as LFU)
    -->


    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="false"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            />


    <!-- We want eternal="true" (with no timeToIdle or timeToLive settings) because Shiro manages session
expirations explicitly.  If we set it to false and then set corresponding timeToIdle and timeToLive properties,
ehcache would evict sessions without Shiro's knowledge, which would cause many problems
(e.g. "My Shiro session timeout is 30 minutes - why isn't a session available after 2 minutes?"
Answer - ehcache expired it due to the timeToIdle property set to 120 seconds.)


diskPersistent=true since we want an enterprise session management feature - ability to use sessions after
even after a JVM restart.  -->
    <cache name="shiro-activeSessionCache"
           maxElementsInMemory="10000"
           eternal="true"
           overflowToDisk="true"
           diskPersistent="true"
           diskExpiryThreadIntervalSeconds="600"/>


    <cache name="org.apache.shiro.realm.SimpleAccountRealm.authorization"
           maxElementsInMemory="100"
           eternal="false"
           timeToLiveSeconds="600"
           overflowToDisk="false"/>


</ehcache>



以上就是在ssm中加入shiro的环境配置

下面是具体的realm以及controller


-------------------------------------------------------------------------------

package cn.ljj.controller;


import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;


@Controller
public class ShiroHandler {


@RequiresRoles("list")
@RequestMapping("/list")
public String list(){
System.out.println("...list...");
return "list";
}

@RequestMapping("/shiro-login")
public String login(HttpServletRequest request){
//如果登陆失败从request中获取认证异常信息,shiroLoginFailure就是shiro异常类的全限定名
String exceptionClassName = (String) request.getAttribute("shiroLoginFailure");
//根据shiro返回的异常类路径判断,抛出指定异常信息
if(exceptionClassName!=null){
if (UnknownAccountException.class.getName().equals(exceptionClassName)) {
//最终会抛给异常处理器
throw new CustomException("账号不存在");
} else if (IncorrectCredentialsException.class.getName().equals(
exceptionClassName)) {
throw new CustomException("用户名/密码错误");
} else if("randomCodeError".equals(exceptionClassName)){
throw new CustomException("验证码错误 ");
}else {
throw new Exception();//最终在异常处理器生成未知错误
}
}
//此方法不处理登陆成功(认证成功),shiro认证成功会自动跳转到上一个请求路径
//登陆失败还到login页面
return "shiro-login";

 }

    @RequestMapping("/logout")
public String logout(HttpSession session)throws Exception{

//session失效
session.invalidate();
//重定向到商品查询页面
return "redirect:/first.action";

     }

}

----------------------------------------------------------------------------

package cn.ljj.realm;


import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;


public class MyRealm extends AuthorizingRealm {


/**
* 授权方法:
* 1. 实际返回的是 SimpleAuthorizationInfo 类的实例
* 2. 可以调用 SimpleAuthorizationInfo 的 addRole 来添加当前登录 user 的权限信息. 
* 3. 可以调用 PrincipalCollection 参数的 getPrimaryPrincipal() 方法来获取用户信息 
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

Object principal = principalCollection.getPrimaryPrincipal();

if("admin".equals(principal)){
info.addRole("admin");
}
if("user".equals(principal)){
info.addRole("list");
}

info.addRole("user");

return info;
}


/**
* 认证方法
* 1. 编写表单: 表单的 action、和 username、password 的参数都是什么 ? 
* 回答: 提交到你想提交的地方, username 和 password 也参数名称都任意. 
* 2. 例如, 提交到了一个 SpringMVC 的 handler: 
* 1). 获取用户名、密码
* 2). 
* Subject currentUser = SecurityUtils.getSubject();
* UsernamePasswordToken token = new UsernamePasswordToken(username, password);
* currentUser.login(token);
* 3. 当 Subject 调用 login 方法时, 即会触发当前的 doGetAuthenticationInfo 方法. 且把 
* UsernamePasswordToken 对象传入, 然后再该方法中执行真正的认证: 访问数据库进行比对. 
* 1). 获取用户名和密码
* 2). 
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
System.out.println(token.getPrincipal());
System.out.println(token.getCredentials());

//1. 从 token 中获取登录的 username! 注意不需要获取 password.

//2. 利用 username 查询数据库得到用户的信息. 

//3. 创建 SimpleAuthenticationInfo 对象并返回. 注意该对象的凭证式从数据库中查询得到的. 
//而不是页面输入的. 实际的密码校验可以交由 Shiro 来完成

//4. 关于密码加密的事: shiro 的密码加密可以非常非常的复杂, 但实现起来却可以非常简单.
//1). 可以选择加密方式: 在当前的 realm 中编写一个 public 类型的不带参数的方法, 使用 @PostConstruct
//注解进行修饰, 在其中来设置密码的匹配方式.
//2). 设置盐值: 盐值一般是从数据库中查询得到的.  
//3). 调用 new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName)
//构造器返回 SimpleAuthenticationInfo 对象:  credentialsSalt 为 
//ByteSource credentialsSalt = new Md5Hash(source);

//登陆的主要信息: 可以是一个实体类的对象, 但该实体类的对象一定是根据 token 的 username 查询得到的. 
Object principal = token.getPrincipal();
//认证信息: 从数据库中查询出来的信息. 密码的比对交给 shiro 去进行比较
String credentials = "afdbaa3ee63a8b4e97196dcfd24b03fc";
//设置盐值: 
String source = "abcdefg";
ByteSource credentialsSalt = new Md5Hash(source);
System.out.println(credentialsSalt); 

//当前 Realm 的 name
String realmName = getName();
SimpleAuthenticationInfo info = 
new SimpleAuthenticationInfo(principal, credentials, 
credentialsSalt, realmName);

return info;
}


//@PostConstruct: 相当于 bean 节点的 init-method 配置. 
public void setCredentialMatcher(){
HashedCredentialsMatcher  credentialsMatcher = new HashedCredentialsMatcher();

credentialsMatcher.setHashAlgorithmName("MD5");
credentialsMatcher.setHashIterations(1024);

setCredentialsMatcher(credentialsMatcher);
}


}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值