Shiro学习笔记

目录

一、Shiro_简介

二、Shiro_HelloWorld

三、Shiro_集成 Spring

四、Shiro_工作流程(1)

五、Shiro_DelegatingFilterProxy

六、Shiro_权限 URL配置细节

七、Shiro_认证思路分析

八、Shiro_实现认证流程

九、Shiro_实现认证Realm

十、Shiro_密码的比对

十一、Shiro_密码的MD5加密

十二、Shiro_密码的MD5盐值加密

十三、Shiro_多 Realm 验证

十四、Shiro_认证策略

十五、Shiro_把 realms 配置给 SecurityManager

十六、Shiro_权限配置

十七、Shiro_授权流程分析

十八、Shiro_多 Realm 授权的通过标准

十九、Shiro_实现授权 Realm

二十、Shiro_标签

二十一、Shiro_权限注解

二十二、Shiro_从数据表中初始化资源和权限

二十三、Shiro_会话管理

二十四、Shiro_SessionDao


一、Shiro_简介

Apache Shiro 是 Java 的一个安全(权限)框架

Shiro可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JavaEE环境。

Shiro可以完成:认证、授权、加密、会话管理、与Web集成、缓存等。

下载:http://shiro.apache.org/

功能简介:

Authentication:认证,Shiro完成登录,密码匹配也是Shiro帮我们完成的

Authorization:授权,当我们点一个链接、点一个按钮的时候,Shiro会帮我们判断你有没有这个权限

Session Management:管理session,我们在web环境下可以使用session,那是http session,在JavaSE环境下也可以使用session,那就是shiro提供的

Cryptography:加密,可以很容易的对密码进行盐值加密

Web Support:对web进行支持,Shiro可以很容易地跟JavaEE应用进行集成

Concurrency:在多线程情况下,进行授权认证

Testing:测试

Caching:Shiro提供了缓存模块,让运行速度更快

Run As:让已经登录的用户以另外一个用户的身份来操练当前的项目和系统

Shiro架构(Shiro外部来看)

从外部来看Shiro,即从应用程序角度的来观察如何使用Shiro完成工作:

Application Code是我们的应用程序,应用程序如果去访问Shiro的话,一定是Subject,这个表示当前用户,就是说你登没登录,你如何登录啊,你是不是可以访问某一个权限啊,都是去搞Subject,它其实是一个门面。核心是SecurityManager,像一个大管家一样,它管理着Shiro的各个组件,Subject的背后就是SecurityManager,当我们去访问一些安全数据的时候,比如说获取用户信息,获取权限信息我们需要用到Realm,它相当于一个SecurityDao

Shiro架构(Shiro内部来看)

上面是Application Code应用程序,应用程序打交道的是Subject,Subject跟Shiro里面的SecurityManager打交道

二、Shiro_HelloWorld

package com.nanjing.shiro.helloworld;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * Simple Quickstart application showing how to use Shiro's API.
 *
 * @since 0.9 RC2
 */
public class Quickstart {

    private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);


    public static void main(String[] args) {

        // The easiest way to create a Shiro SecurityManager with configured
        // realms, users, roles and permissions is to use the simple INI config.
        // We'll do that by using a factory that can ingest a .ini file and
        // return a SecurityManager instance:

        // Use the shiro.ini file at the root of the classpath
        // (file: and url: prefixes load from files and urls respectively):
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();

        // for this simple example quickstart, make the SecurityManager
        // accessible as a JVM singleton.  Most applications wouldn't do this
        // and instead rely on their container configuration or web.xml for
        // webapps.  That is outside the scope of this simple quickstart, so
        // we'll just do the bare minimum so you can continue to get a feel
        // for things.
        SecurityUtils.setSecurityManager(securityManager);

        // Now that a simple Shiro environment is set up, let's see what you can do:

        // get the currently executing user:
        // 获取当前的 Subject. 调用 SecurityUtils.getSubject();
        Subject currentUser = SecurityUtils.getSubject();

        // Do some stuff with a Session (no need for a web or EJB container!!!)
        // 测试使用 Session
        // 获取 Session: Subject#getSession()
        Session session = currentUser.getSession();
        session.setAttribute("someKey", "aValue");
        String value = (String) session.getAttribute("someKey");
        if (value.equals("aValue")) {
            log.info("---> Retrieved the correct value! [" + value + "]");
        }

        // let's login the current user so we can check against roles and permissions:
        // 测试当前的用户是否已经被认证. 即是否已经登录.
        // 调动 Subject 的 isAuthenticated()
        if (!currentUser.isAuthenticated()) {
            // 把用户名和密码封装为 UsernamePasswordToken 对象
            UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
            // rememberme
            token.setRememberMe(true);
            try {
                // 执行登录.
                currentUser.login(token);
            }
            // 若没有指定的账户, 则 shiro 将会抛出 UnknownAccountException 异常.
            catch (UnknownAccountException uae) {
                log.info("----> There is no user with username of " + token.getPrincipal());
                return;
            }
            // 若账户存在, 但密码不匹配, 则 shiro 会抛出 IncorrectCredentialsException 异常。
            catch (IncorrectCredentialsException ice) {
                log.info("----> Password for account " + token.getPrincipal() + " was incorrect!");
                return;
            }
            // 用户被锁定的异常 LockedAccountException
            catch (LockedAccountException lae) {
                log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                        "Please contact your administrator to unlock it.");
            }
            // ... catch more exceptions here (maybe custom ones specific to your application?
            // 所有认证时异常的父类.
            catch (AuthenticationException ae) {
                //unexpected condition?  error?
            }
        }

        //say who they are:
        //print their identifying principal (in this case, a username):
        log.info("----> User [" + currentUser.getPrincipal() + "] logged in successfully.");

        //test a role:
        // 测试是否有某一个角色. 调用 Subject 的 hasRole 方法.
        if (currentUser.hasRole("schwartz")) {
            log.info("----> May the Schwartz be with you!");
        } else {
            log.info("----> Hello, mere mortal.");
            return;
        }

        //test a typed permission (not instance-level)
        // 测试用户是否具备某一个行为. 调用 Subject 的 isPermitted() 方法。
        if (currentUser.isPermitted("lightsaber:weild")) {
            log.info("----> You may use a lightsaber ring.  Use it wisely.");
        } else {
            log.info("Sorry, lightsaber rings are for schwartz masters only.");
        }

        //a (very powerful) Instance Level permission:
        // 测试用户是否具备某一个行为.
        if (currentUser.isPermitted("user:delete:zhangsan")) {
            log.info("----> You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  " +
                    "Here are the keys - have fun!");
        } else {
            log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
        }

        //all done - log out!
        // 执行登出. 调用 Subject 的 Logout() 方法.
        System.out.println("---->" + currentUser.isAuthenticated());

        currentUser.logout();

        System.out.println("---->" + currentUser.isAuthenticated());

        System.exit(0);
    }
}

三、Shiro_集成 Spring

步骤1:web.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!-- needed for ContextLoaderListener -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

    <!-- Bootstraps the root web application context before servlet initialization -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- The front controller of this Spring Web application, responsible for handling all application requests -->
    <servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- Map all requests to the DispatcherServlet for handling -->
    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- Shiro Filter is defined in the spring application context: -->
    <!--
    1. 配置  Shiro 的 shiroFilter.
    2. DelegatingFilterProxy 实际上是 Filter 的一个代理对象. 默认情况下, Spring 会到 IOC 容器中查找和
    <filter-name> 对应的 filter bean. 也可以通过 targetBeanName 的初始化参数来配置 filter bean 的 id.
    -->
    <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>
</web-app>

步骤2:spring-servlet.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:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
	
	<context:component-scan base-package="com.nanjing.shiro"></context:component-scan>
	
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>
	
	<mvc:annotation-driven></mvc:annotation-driven>

	<mvc:default-servlet-handler/>

</beans>

步骤3:applicationContext.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">

	<!-- =========================================================
         Shiro Core Components - Not Spring Specific
         ========================================================= -->
	<!-- Shiro's main business-tier object for web-enabled applications
         (use DefaultSecurityManager instead when there is no web environment)-->
	<!--
    1. 配置 SecurityManager!
    -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="cacheManager" ref="cacheManager"/>
<!--		<property name="authenticator" ref="authenticator"></property>-->

		<property name="sessionMode" value="native"/>
		<property name="realms" ref="jdbcRealm"/>
<!--			<list>-->
<!--				<ref bean="jdbcRealm"/>-->
<!--				<ref bean="secondRealm"/>-->
<!--			</list>-->
<!--		</property>-->

<!--		<property name="rememberMeManager.cookie.maxAge" value="10"></property>-->
	</bean>

	<!-- Let's use some enterprise caching support for better performance.  You can replace this with any enterprise
         caching framework implementation that you like (Terracotta+Ehcache, Coherence, GigaSpaces, etc -->
	<!--
    2. 配置 CacheManager.
    2.1 需要加入 ehcache 的 jar 包及配置文件.
    -->
	<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
		<!-- Set a net.sf.ehcache.CacheManager instance here if you already have one.  If not, a new one
             will be creaed with a default config:
             <property name="cacheManager" ref="ehCacheManager"/> -->
		<!-- If you don't have a pre-built net.sf.ehcache.CacheManager instance to inject, but you want
             a specific Ehcache configuration to be used, specify that here.  If you don't, a default
             will be used.: -->
		<property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
	</bean>

<!--	<bean id="authenticator"-->
<!--		  class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">-->
<!--		<property name="authenticationStrategy">-->
<!--			<bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"></bean>-->
<!--		</property>-->
<!--	</bean>-->

	<!-- Used by the SecurityManager to access security data (users, roles, etc).
         Many other realm implementations can be used too (PropertiesRealm,
         LdapRealm, etc. -->
	<!--
        3. 配置 Realm
        3.1 直接配置实现了 org.apache.shiro.realm.Realm 接口的 bean
    -->
	<bean id="jdbcRealm" class="com.nanjing.shiro.realms.ShiroRealm">
<!--		<property name="credentialsMatcher">-->
<!--			<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">-->
<!--				<property name="hashAlgorithmName" value="MD5"></property>-->
<!--				<property name="hashIterations" value="1024"></property>&lt;!&ndash;加密次数&ndash;&gt;-->
<!--			</bean>-->
<!--		</property>-->
	</bean>

<!--	<bean id="secondRealm" class="com.atguigu.shiro.realms.SecondRealm">-->
<!--		<property name="credentialsMatcher">-->
<!--			<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">-->
<!--				<property name="hashAlgorithmName" value="SHA1"></property>-->
<!--				<property name="hashIterations" value="1024"></property>-->
<!--			</bean>-->
<!--		</property>-->
<!--	</bean>-->

	<!-- =========================================================
         Shiro Spring-specific integration
         ========================================================= -->
	<!-- Post processor that automatically invokes init() and destroy() methods
         for Spring-configured Shiro objects so you don't have to
         1) specify an init-method and destroy-method attributes for every bean
            definition and
         2) even know which Shiro objects require these methods to be
            called. -->
	<!--
    4. 配置 LifecycleBeanPostProcessor. 可以自动的来调用配置在 Spring IOC 容器中 shiro bean 的生命周期方法.
    -->
	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

	<!-- Enable Shiro Annotations for Spring-configured beans.  Only run after
         the lifecycleBeanProcessor has run: -->
	<!--
    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>

	<!-- Define the Shiro Filter here (as a FactoryBean) instead of directly in web.xml -
         web.xml uses the DelegatingFilterProxy to access this bean.  This allows us
         to wire things with more control as well utilize nice Spring things such as
         PropertiesPlaceholderConfigurer and abstract beans or anything else we might need: -->
	<!--
    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="/list.jsp"/>
		<property name="unauthorizedUrl" value="/unauthorized.jsp"/><!--没有权限的页面-->

<!--		<property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"></property>-->

		<!--
            配置哪些页面需要受保护.
            以及访问这些页面需要的权限.
            1). anon 可以被匿名访问
            2). authc 必须认证(即登录)后才可能访问的页面.
            3). logout 登出.
            4). roles 角色过滤器
        -->
        <property name="filterChainDefinitions">
            <value>
                /login.jsp = anon
                /shiro/login = anon
                /shiro/logout = logout
<!--                -->
<!--                /user.jsp = roles[user]-->
<!--                /admin.jsp = roles[admin]-->

                # everything else requires authentication:
                /** = authc
            </value>
        </property>

	</bean>

	<!-- 配置一个 bean, 该 bean 实际上是一个 Map. 通过实例工厂方法的方式 -->
<!--	<bean id="filterChainDefinitionMap"-->
<!--		  factory-bean="filterChainDefinitionMapBuilder" factory-method="buildFilterChainDefinitionMap"></bean>-->

<!--	<bean id="filterChainDefinitionMapBuilder"-->
<!--		  class="com.atguigu.shiro.factory.FilterChainDefinitionMapBuilder"></bean>-->

<!--	<bean id="shiroService"-->
<!--		  class="com.atguigu.shiro.services.ShiroService"></bean>-->

</beans>

四、Shiro_工作流程(1)

1、

2、

五、Shiro_DelegatingFilterProxy

默认值是filter-name所对应的值,

步骤1:web.xml文件

 <!-- Shiro Filter is defined in the spring application context: -->
    <!--
    1. 配置  Shiro 的 shiroFilter.
    2. DelegatingFilterProxy 实际上是 Filter 的一个代理对象. 默认情况下, Spring 会到 IOC 容器中查找和
    <filter-name> 对应的 filter bean. 也可以通过 targetBeanName 的初始化参数来配置 filter bean 的 id.
    -->
    <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>
<!--        <init-param>-->
<!--            <param-name>targetBeanName</param-name>-->
<!--            <param-value>abc</param-value>-->
<!--        </init-param>-->
    </filter>

    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

步骤2:applicationContext.xml

<!--
    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="/list.jsp"/>
		<property name="unauthorizedUrl" value="/unauthorized.jsp"/><!--没有权限的页面-->

<!--		<property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"></property>-->

		<!--
            配置哪些页面需要受保护.
            以及访问这些页面需要的权限.
            1). anon 可以被匿名访问
            2). authc 必须认证(即登录)后才可能访问的页面.
            3). logout 登出.
            4). roles 角色过滤器
        -->
        <property name="filterChainDefinitions">
            <value>
                /login.jsp = anon
                /shiro/login = anon
                /shiro/logout = logout
<!--                -->
<!--                /user.jsp = roles[user]-->
<!--                /admin.jsp = roles[admin]-->

                # everything else requires authentication:
                /** = authc
            </value>
        </property>

	</bean>

六、Shiro_权限 URL配置细节

<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="/list.jsp"/>
		<property name="unauthorizedUrl" value="/unauthorized.jsp"/><!--没有权限的页面-->

<!--		<property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"></property>-->

		<!--
            配置哪些页面需要受保护.
            以及访问这些页面需要的权限.
            1). anon 可以被匿名访问
            2). authc 必须认证(即登录)后才可能访问的页面.
            3). logout 登出.
            4). roles 角色过滤器
        -->
        <property name="filterChainDefinitions">
            <value>
                /login.jsp = anon
                /shiro/login = anon
                /shiro/logout = logout
<!--                -->
<!--                /user.jsp = roles[user]-->
<!--                /admin.jsp = roles[admin]-->

                # everything else requires authentication:
                /** = authc
            </value>
        </property>

	</bean>

七、Shiro_认证思路分析

1. 获取当前的 Subject. 调用 SecurityUtils.getSubject();
2. 测试当前的用户是否已经被认证. 即是否已经登录. 调用 Subject 的 isAuthenticated() 
3. 若没有被认证, 则把用户名和密码封装为 UsernamePasswordToken 对象
1). 创建一个表单页面
2). 把请求提交到 SpringMVC 的 Handler
3). 获取用户名和密码. 
4. 执行登录: 调用 Subject 的 login(AuthenticationToken) 方法. 
5. 自定义 Realm 的方法, 从数据库中获取对应的记录, 返回给 Shiro.
1). 实际上需要继承 org.apache.shiro.realm.AuthenticatingRealm 类
2). 实现 doGetAuthenticationInfo(AuthenticationToken) 方法. 

why???

1、

2、

3、

4、

5、

6、

7、


6. 由 shiro 完成对密码的比对. 

八、Shiro_实现认证流程

步骤1:login.jsp文件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<h4>login page</h4>

<form action="shiro/login" method="POST">
    username: <input type="text" name="username"/>
    <br><br>

    password: <input type="password" name="password"/>
    <br><br>

    <input type="submit" value="Submit"/>
</form>

</body>
</html>

步骤2:ShiroHandler.java文件

@Controller
@RequestMapping("/shiro")
public class ShiroHandler {

	@RequestMapping("/login")
	public String login(@RequestParam("username") String username,
						@RequestParam("password") String password){
		Subject currentUser = SecurityUtils.getSubject();

		if (!currentUser.isAuthenticated()) {
			// 把用户名和密码封装为 UsernamePasswordToken 对象
			UsernamePasswordToken token = new UsernamePasswordToken(username, password);
			// rememberme
			token.setRememberMe(true);
			try {
				System.out.println("1. " + token.hashCode());
				// 执行登录.
				currentUser.login(token);
			}
			// ... catch more exceptions here (maybe custom ones specific to your application?
			// 所有认证时异常的父类.
			catch (AuthenticationException ae) {
				//unexpected condition?  error?
				System.out.println("登录失败: " + ae.getMessage());
			}
		}

		return "redirect:/list.jsp";
	}

}

步骤3:ShiroRealm.java文件

public class ShiroRealm extends AuthorizingRealm {

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
        System.out.println("[FirstRealm] doGetAuthenticationInfo");
        return info;
    }

九、Shiro_实现认证Realm

步骤1:

public class ShiroRealm extends AuthorizingRealm {

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
        System.out.println("[FirstRealm] doGetAuthenticationInfo");

        //1. 把 AuthenticationToken 转换为 UsernamePasswordToken
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;

        //2. 从 UsernamePasswordToken 中来获取 username
        String username = upToken.getUsername();

        //3. 调用数据库的方法, 从数据库中查询 username 对应的用户记录
        System.out.println("从数据库中获取 username: " + username + " 所对应的用户信息.");

        //4. 若用户不存在, 则可以抛出 UnknownAccountException 异常
        if("unknown".equals(username)){
            throw new UnknownAccountException("用户不存在!");
        }

        //5. 根据用户信息的情况, 决定是否需要抛出其他的 AuthenticationException 异常.
        if("monster".equals(username)){
            throw new LockedAccountException("用户被锁定");
        }

        //6. 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo
        //以下信息是从数据库中获取的.
        //1). principal: 认证的实体信息. 可以是 username, 也可以是数据表对应的用户的实体类对象.
        Object principal = username;
        //2). credentials: 密码.
        Object credentials = 123456;
        //3). realmName: 当前 realm 对象的 name. 调用父类的 getName() 方法即可
        String realmName = getName();
       
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, realmName);
        return info;
    }
}

步骤2:list.jsp文件,实现退出操作,会有shiro的缓存

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<h1>list page</h1>

<br><br>
<a href="shiro/logout">Logout</a>

</body>
</html>

步骤3:applicationContext.xml文件

<!--
    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="/list.jsp"/>
		<property name="unauthorizedUrl" value="/unauthorized.jsp"/><!--没有权限的页面-->

<!--		<property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"></property>-->

		<!--
            配置哪些页面需要受保护.
            以及访问这些页面需要的权限.
            1). anon 可以被匿名访问
            2). authc 必须认证(即登录)后才可能访问的页面.
            3). logout 登出
        -->
        <property name="filterChainDefinitions">
            <value>
                /login.jsp = anon
                /shiro/login = anon
                /shiro/logout = logout

                # everything else requires authentication:
                /** = authc
            </value>
        </property>

	</bean>

十、Shiro_密码的比对

密码的比对:
通过 AuthenticatingRealm 的 credentialsMatcher 属性来进行的密码的比对!

1、

2、可以使用MD5 进行颜值加密

十一、Shiro_密码的MD5加密

1. 如何把一个字符串加密为 MD5 
2. 替换当前 Realm 的 credentialsMatcher 属性. 直接使用 HashedCredentialsMatcher 对象, 并设置加密算法即可. 

applicationContext.xml文件

<!--
        3. 配置 Realm
        3.1 直接配置实现了 org.apache.shiro.realm.Realm 接口的 bean
    -->
	<bean id="jdbcRealm" class="com.nanjing.shiro.realms.ShiroRealm">
		<property name="credentialsMatcher">
			<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
				<property name="hashAlgorithmName" value="MD5"></property>
				<property name="hashIterations" value="1024"></property><!--加密次数-->
			</bean>
		</property>
	</bean>

加密的源码

测试

public class ShiroRealm extends AuthorizingRealm {

    public static void main(String[] args) {
        String hashAlgorithmName = "MD5";
        Object credentials = "123456";
        Object salt = ByteSource.Util.bytes("user");;
        int hashIterations = 1024;

        Object result = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
        System.out.println(result);
    }

十二、Shiro_密码的MD5盐值加密

1. 为什么使用 MD5 盐值加密: 
2. 如何做到:
1). 在 doGetAuthenticationInfo 方法返回值创建 SimpleAuthenticationInfo 对象的时候, 需要使用
SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName) 构造器
2). 使用 ByteSource.Util.bytes() 来计算盐值. 
3). 盐值需要唯一: 一般使用随机字符串或 user id
4). 使用 new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations); 来计算盐值加密后的密码的值.

public class ShiroRealm extends AuthorizingRealm {

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
        System.out.println("[FirstRealm] doGetAuthenticationInfo");

        //1. 把 AuthenticationToken 转换为 UsernamePasswordToken
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;

        //2. 从 UsernamePasswordToken 中来获取 username
        String username = upToken.getUsername();

        //3. 调用数据库的方法, 从数据库中查询 username 对应的用户记录
        System.out.println("从数据库中获取 username: " + username + " 所对应的用户信息.");

        //4. 若用户不存在, 则可以抛出 UnknownAccountException 异常
        if("unknown".equals(username)){
            throw new UnknownAccountException("用户不存在!");
        }

        //5. 根据用户信息的情况, 决定是否需要抛出其他的 AuthenticationException 异常.
        if("monster".equals(username)){
            throw new LockedAccountException("用户被锁定");
        }

        //6. 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo
        //以下信息是从数据库中获取的.
        //1). principal: 认证的实体信息. 可以是 username, 也可以是数据表对应的用户的实体类对象.
        Object principal = username;
        //2). credentials: 密码.
        Object credentials = null; //"fc1709d0a95a6be30bc5926fdb7f22f4";
        if("admin".equals(username)){
            credentials = "038bdaf98f2037b31f1e75b5b4c9b26e";
        }else if("user".equals(username)){
            credentials = "098d2c478e9c11555ce2823231e02ec1";
        }

        //3). realmName: 当前 realm 对象的 name. 调用父类的 getName() 方法即可
        String realmName = getName();
        //4). 盐值.
        ByteSource credentialsSalt = ByteSource.Util.bytes(username);

        SimpleAuthenticationInfo info = null; //new SimpleAuthenticationInfo(principal, credentials, realmName);
        info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
        return info;
    }

    public static void main(String[] args) {
        String hashAlgorithmName = "MD5";
        Object credentials = "123456";
        Object salt = ByteSource.Util.bytes("user");;
        int hashIterations = 1024;

        Object result = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
        System.out.println(result);
    }

十三、Shiro_多 Realm 验证

步骤1:

步骤2:

步骤3:

步骤4:

步骤5:

步骤1:

public class SecondRealm extends AuthenticatingRealm {

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken token) throws AuthenticationException {
		System.out.println("[SecondReaml] doGetAuthenticationInfo");

		//1. 把 AuthenticationToken 转换为 UsernamePasswordToken
		UsernamePasswordToken upToken = (UsernamePasswordToken) token;

		//2. 从 UsernamePasswordToken 中来获取 username
		String username = upToken.getUsername();

		//3. 调用数据库的方法, 从数据库中查询 username 对应的用户记录
		System.out.println("从数据库中获取 username: " + username + " 所对应的用户信息.");

		//4. 若用户不存在, 则可以抛出 UnknownAccountException 异常
		if("unknown".equals(username)){
			throw new UnknownAccountException("用户不存在!");
		}

		//5. 根据用户信息的情况, 决定是否需要抛出其他的 AuthenticationException 异常.
		if("monster".equals(username)){
			throw new LockedAccountException("用户被锁定");
		}

		//6. 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo
		//以下信息是从数据库中获取的.
		//1). principal: 认证的实体信息. 可以是 username, 也可以是数据表对应的用户的实体类对象.
		Object principal = username;
		//2). credentials: 密码.
		Object credentials = null; //"fc1709d0a95a6be30bc5926fdb7f22f4";
		if("admin".equals(username)){
			credentials = "ce2f6417c7e1d32c1d81a797ee0b499f87c5de06";
		}else if("user".equals(username)){
			credentials = "073d4c3ae812935f23cb3f2a71943f49e082a718";
		}

		//3). realmName: 当前 realm 对象的 name. 调用父类的 getName() 方法即可
		String realmName = getName();
		//4). 盐值.
		ByteSource credentialsSalt = ByteSource.Util.bytes(username);

		SimpleAuthenticationInfo info = null; //new SimpleAuthenticationInfo(principal, credentials, realmName);
		info = new SimpleAuthenticationInfo("secondRealmName", credentials, credentialsSalt, realmName);
		return info;
	}

	public static void main(String[] args) {
		String hashAlgorithmName = "SHA1";
		Object credentials = "123456";
		Object salt = ByteSource.Util.bytes("admin");;
		int hashIterations = 1024;

		Object result = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
		System.out.println(result);
	}
}

步骤2:applicationContext.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">

	<!-- =========================================================
         Shiro Core Components - Not Spring Specific
         ========================================================= -->
	<!-- Shiro's main business-tier object for web-enabled applications
         (use DefaultSecurityManager instead when there is no web environment)-->
	<!--
    1. 配置 SecurityManager!
    -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="cacheManager" ref="cacheManager"/>
		<property name="authenticator" ref="authenticator"></property>
	</bean>

	<!-- Let's use some enterprise caching support for better performance.  You can replace this with any enterprise
         caching framework implementation that you like (Terracotta+Ehcache, Coherence, GigaSpaces, etc -->
	<!--
    2. 配置 CacheManager.
    2.1 需要加入 ehcache 的 jar 包及配置文件.
    -->
	<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
		<!-- Set a net.sf.ehcache.CacheManager instance here if you already have one.  If not, a new one
             will be creaed with a default config:
             <property name="cacheManager" ref="ehCacheManager"/> -->
		<!-- If you don't have a pre-built net.sf.ehcache.CacheManager instance to inject, but you want
             a specific Ehcache configuration to be used, specify that here.  If you don't, a default
             will be used.: -->
		<property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
	</bean>

	<bean id="authenticator"
		  class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
		<property name="realms">
			<list>
				<ref bean="jdbcRealm"/>
				<ref bean="secondRealm"/>
			</list>
		</property>
	</bean>

	<!-- Used by the SecurityManager to access security data (users, roles, etc).
         Many other realm implementations can be used too (PropertiesRealm,
         LdapRealm, etc. -->
	<!--
        3. 配置 Realm
        3.1 直接配置实现了 org.apache.shiro.realm.Realm 接口的 bean
    -->
	<bean id="jdbcRealm" class="com.nanjing.shiro.realms.ShiroRealm">
		<property name="credentialsMatcher">
			<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
				<property name="hashAlgorithmName" value="MD5"></property>
				<property name="hashIterations" value="1024"></property><!--加密次数-->
			</bean>
		</property>
	</bean>

	<bean id="secondRealm" class="com.nanjing.shiro.realms.SecondRealm">
		<property name="credentialsMatcher">
			<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
				<property name="hashAlgorithmName" value="SHA1"></property>
				<property name="hashIterations" value="1024"></property>
			</bean>
		</property>
	</bean>

	<!-- =========================================================
         Shiro Spring-specific integration
         ========================================================= -->
	<!-- Post processor that automatically invokes init() and destroy() methods
         for Spring-configured Shiro objects so you don't have to
         1) specify an init-method and destroy-method attributes for every bean
            definition and
         2) even know which Shiro objects require these methods to be
            called. -->
	<!--
    4. 配置 LifecycleBeanPostProcessor. 可以自动的来调用配置在 Spring IOC 容器中 shiro bean 的生命周期方法.
    -->
	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

	<!-- Enable Shiro Annotations for Spring-configured beans.  Only run after
         the lifecycleBeanProcessor has run: -->
	<!--
    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>

	<!-- Define the Shiro Filter here (as a FactoryBean) instead of directly in web.xml -
         web.xml uses the DelegatingFilterProxy to access this bean.  This allows us
         to wire things with more control as well utilize nice Spring things such as
         PropertiesPlaceholderConfigurer and abstract beans or anything else we might need: -->
	<!--
    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="/list.jsp"/>
		<property name="unauthorizedUrl" value="/unauthorized.jsp"/><!--没有权限的页面-->

<!--		<property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"></property>-->

		<!--
            配置哪些页面需要受保护.
            以及访问这些页面需要的权限.
            1). anon 可以被匿名访问
            2). authc 必须认证(即登录)后才可能访问的页面.
            3). logout 登出.
            4). roles 角色过滤器
        -->
        <property name="filterChainDefinitions">
            <value>
                /login.jsp = anon
                /shiro/login = anon
                /shiro/logout = logout
<!--                -->
<!--                /user.jsp = roles[user]-->
<!--                /admin.jsp = roles[admin]-->

                # everything else requires authentication:
                /** = authc
            </value>
        </property>

	</bean>

</beans>

十四、Shiro_认证策略

<bean id="authenticator"
		  class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
		<property name="authenticationStrategy">
			<bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"></bean>
		</property>
		<property name="realms">
			<list>
				<ref bean="jdbcRealm"/>
				<ref bean="secondRealm"/>
			</list>
		</property>
	</bean>

十五、Shiro_把 realms 配置给 SecurityManager

源码分析

<!--
    1. 配置 SecurityManager!
    -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="cacheManager" ref="cacheManager"/>
		<property name="authenticator" ref="authenticator"></property>

		<!--我们在做授权的时候,我们需要从securityManager去读那个realms的-->
		<property name="realms">
			<list>
				<ref bean="jdbcRealm"/>
				<ref bean="secondRealm"/>
			</list>
		</property>
	</bean>

十六、Shiro_权限配置

新建admin.jsp和user.jsp文件

步骤1:list.jsp文件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>list page</h1>

    <br><br>
    <a href="admin.jsp">Admin Page</a>

    <br><br>
    <a href="user.jsp">User Page</a>

<br><br>
<a href="shiro/logout">Logout</a>

</body>
</html>

步骤2:applicationContext.xml文件

<!--
    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="/list.jsp"/>
		<property name="unauthorizedUrl" value="/unauthorized.jsp"/><!--没有权限的页面-->

<!--		<property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"></property>-->

		<!--
            配置哪些页面需要受保护.
            以及访问这些页面需要的权限.
            1). anon 可以被匿名访问
            2). authc 必须认证(即登录)后才可能访问的页面.
            3). logout 登出.
            4). roles 角色过滤器
        -->
        <property name="filterChainDefinitions">
            <value>
                /login.jsp = anon
                /shiro/login = anon
                /shiro/logout = logout

                /user.jsp = roles[user]
                /admin.jsp = roles[admin]

                # everything else requires authentication:
                /** = authc
            </value>
        </property>

	</bean>

十七、Shiro_授权流程分析

1. 授权需要继承 AuthorizingRealm 类, 并实现其 doGetAuthorizationInfo 方法
2. AuthorizingRealm 类继承自 AuthenticatingRealm, 但没有实现 AuthenticatingRealm 中的 
doGetAuthenticationInfo, 所以认证和授权只需要继承 AuthorizingRealm 就可以了. 同时实现他的两个抽象方法.

步骤1:

步骤2:

步骤3:

public class TestRealm extends AuthorizingRealm {

	//用于授权的方法.
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		// TODO Auto-generated method stub
		return null;
	}

	//用于认证的方法
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken token) throws AuthenticationException {
		// TODO Auto-generated method stub
		return null;
	}

}

十八、Shiro_多 Realm 授权的通过标准

只要有一个授权通过的话,它就可以return true;

十九、Shiro_实现授权 Realm

//授权会被 shiro 回调的方法
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        //1. 从 PrincipalCollection 中来获取登录用户的信息
        Object principal = principals.getPrimaryPrincipal();

        //2. 利用登录的用户的信息来用户当前用户的角色或权限(可能需要查询数据库)
        Set<String> roles = new HashSet<>();
        roles.add("user");
        if("admin".equals(principal)){
            roles.add("admin");
        }

        //3. 创建 SimpleAuthorizationInfo, 并设置其 reles 属性.
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);

        //4. 返回 SimpleAuthorizationInfo 对象.
        return info;
    }

二十、Shiro_标签

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>list page</h1>

Welcome: <shiro:principal></shiro:principal>

<shiro:hasRole name="admin">
    <br><br>
    <a href="admin.jsp">Admin Page</a>
</shiro:hasRole>

<shiro:hasRole name="user">
    <br><br>
    <a href="user.jsp">User Page</a>
</shiro:hasRole>

<%--<br><br>--%>
<%--<a href="shiro/testShiroAnnotation">Test ShiroAnnotation</a>--%>

<br><br>
<a href="shiro/logout">Logout</a>

</body>
</html>

二十一、Shiro_权限注解

步骤1:list.jsp文件

<a href="shiro/testShiroAnnotation">Test ShiroAnnotation</a>

步骤2:ShiroHandler.java文件

@Controller
@RequestMapping("/shiro")
public class ShiroHandler {

	@Autowired
	private ShiroService shiroService;

	@RequestMapping("/testShiroAnnotation")
	public String testShiroAnnotation(HttpSession session){
		session.setAttribute("key", "value12345");
		shiroService.testMethod();
		return "redirect:/list.jsp";
	}

步骤3:applicationContext.xml文件

	<bean id="shiroService"
		  class="com.nanjing.shiro.services.ShiroService"></bean>

步骤4:ShiroService.java文件

public class ShiroService {
	
	@RequiresRoles({"admin"})
	public void testMethod(){
		System.out.println("testMethod, time: " + new Date());
		
		Session session = SecurityUtils.getSubject().getSession();
		Object val = session.getAttribute("key");
		
		System.out.println("Service SessionVal: " + val);
	}
	
}
 

二十二、Shiro_从数据表中初始化资源和权限

步骤1:

<!--
    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="/list.jsp"/>
		<property name="unauthorizedUrl" value="/unauthorized.jsp"/><!--没有权限的页面-->

		<property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"></property>

		<!--
            配置哪些页面需要受保护.
            以及访问这些页面需要的权限.
            1). anon 可以被匿名访问
            2). authc 必须认证(即登录)后才可能访问的页面.
            3). logout 登出.
            4). roles 角色过滤器
        -->
		<!--
        <property name="filterChainDefinitions">
            <value>
                /login.jsp = anon
                /shiro/login = anon
                /shiro/logout = logout

                /user.jsp = roles[user]
                /admin.jsp = roles[admin]

                # everything else requires authentication:
                /** = authc
            </value>
        </property>
        -->
	</bean>

	<!-- 配置一个 bean, 该 bean 实际上是一个 Map. 通过实例工厂方法的方式 -->
	<bean id="filterChainDefinitionMap"
		  factory-bean="filterChainDefinitionMapBuilder" factory-method="buildFilterChainDefinitionMap"></bean>

	<bean id="filterChainDefinitionMapBuilder"
		  class="com.nanjing.shiro.factory.FilterChainDefinitionMapBuilder"></bean>

步骤2:

public class FilterChainDefinitionMapBuilder {

	public LinkedHashMap<String, String> buildFilterChainDefinitionMap(){
		LinkedHashMap<String, String> map = new LinkedHashMap<>();
		
		map.put("/login.jsp", "anon");
		map.put("/shiro/login", "anon");
		map.put("/shiro/logout", "logout");
		map.put("/user.jsp", "authc,roles[user]");
		map.put("/admin.jsp", "authc,roles[admin]");
		map.put("/list.jsp", "user");
		
		map.put("/**", "authc");
		
		return map;
	}
	
}

二十三、Shiro_会话管理

我们在传统的web应用里面,没办法在service里面访问HttpSession的。handler层的api,我们在service层是不能够访问的,现在我有Shiro的session就可以使用了

步骤1:在controller设置session值,然后在service层可以访问

@Controller
@RequestMapping("/shiro")
public class ShiroHandler {

	@Autowired
	private ShiroService shiroService;

	@RequestMapping("/testShiroAnnotation")
	public String testShiroAnnotation(HttpSession session){
		session.setAttribute("key", "value12345");
		shiroService.testMethod();
		return "redirect:/list.jsp";
	}

步骤2:

public class ShiroService {
	
	@RequiresRoles({"admin"})
	public void testMethod(){
		System.out.println("testMethod, time: " + new Date());
		
		Session session = SecurityUtils.getSubject().getSession();
		Object val = session.getAttribute("key");
		
		System.out.println("Service SessionVal: " + val);
	}
	
}
 

二十四、Shiro_SessionDao

它可以把session写到数据库里面,然后对那个session来进行增删改查操作

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值