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类,org.apache.shiro.realm.AuthenticatingRealm间接实现了Realm接口
    2)实现doGetAuthenticationInfo(AuthenticationToken)方法。
6、由shiro完成对密码的比对。

项目结构

1、整合spirng和shiro

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">

	<!-- 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>

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


	<!-- 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>

</web-app>

spring配置文件

<?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">


	<!-- 配置SecurityManager -->
	<bean id="securityManager"
		class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="cacheManager" ref="cacheManager" />
		<!-- Single realm app. If you have multiple realms, use the 'realms' property 
			instead. -->
		<property name="sessionMode" value="native" />
		<property name="realm" ref="jdbcRealm" />
	</bean>

	<!-- 配置cacheManager
			需要加入ehcache的配置文件和jar包
	 -->
	<bean id="cacheManager"	class="org.apache.shiro.cache.ehcache.EhCacheManager">
		<property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
	</bean>

	<!-- Used by the SecurityManager to access security data (users, roles, 
		etc). Many other realm implementations can be used too (PropertiesRealm, 
		LdapRealm, etc. -->
	<!-- 直接使用实现了Realm接口的bean -->
	<bean id="jdbcRealm" class="com.atguigu.shiro.realms.ShiroRealm"></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. -->
	<!-- 配置生命周期的后置处理器,自动调用spirng的IOC容器中shiro的方法 -->
	<bean id="lifecycleBeanPostProcessor"
		class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

	<!-- Enable Shiro Annotations for Spring-configured beans. Only run after 
		the lifecycleBeanProcessor has run: 
		启用shiro的生命周期注解,其依赖lifecycleBeanPostProcessor,所以在配置了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>

	<!--
		这里的id必须于web.xml文件中配置的DelegatingFilterProxy的filter-name一样
		若不一样则抛出NoSuchBeanDefinitionException 
		因为shiro会到spring的IOC容器中找shiroFilter对应的bean
		
		若不一致的话也可以在fileter的初始化参数中配置targetBeanName,将这里的shiroFilter换成targetBeanName的值就可以了
	-->
	<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" />
		<!-- 
			配置哪些页面需要保护
			以及访问页面的权限
			拦截器:(这里的url支持Ant风格模式)
			1).anon 可以被匿名访问
			2) .authc 需要认证才能访问
			这里的url优先匹配
		 -->
		<property name="filterChainDefinitions">
			<value>
				/login.jsp = anon
				/shiro/login = anon
				
				# everything else requires authentication:
				/** = authc
				
				/list.jsp = anon
			</value>
		</property>
	</bean>


</beans>

ehcache.xml

<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"/>


    <!--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 before 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 before 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 before 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 before 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、编码实现

login.jsp

	<form action="shiro/login" method="post">
		UserName:<input name="username" type="text"/>
		
		<br><br>
		
		PassWord:<input name="password" type="password"/>
		
		<br><br>
		
		<input type="submit" value="Submit"/>
	</form>

ShiroHandler.java

package com.atguigu.shiro.handlers;

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

/**
 * 实现Shiro认证
 * @author Lee
 *
 */
@Controller
@RequestMapping("/shiro")
public class ShiroHandler {

	@RequestMapping(value="/login",method=RequestMethod.POST)
	public String login(@RequestParam("username") String username,@RequestParam("password") String password) {
		System.out.println(username + "" + password);
		Subject currentUser = SecurityUtils.getSubject();
		
		if (!currentUser.isAuthenticated()) {
			UsernamePasswordToken token = new UsernamePasswordToken(username, password);
			token.setRememberMe(true);
			System.out.println(token.hashCode());
			try {
				currentUser.login(token);
			} catch (AuthenticationException e) {
				System.out.println("登陆失败");
				e.printStackTrace();
			}
		}
		return "redirect:/list.jsp";
	}
	
}

ShiroRealm.java

package com.atguigu.shiro.realms;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.realm.AuthenticatingRealm;

/**
 * 
 * @author Lee
 *
 */
public class ShiroRealm extends AuthenticatingRealm{

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		System.out.println("doGetAuthenticationInfo" + token);
		System.out.println(token.hashCode());
		return null;
	}

}

猜你喜欢

转载自blog.csdn.net/qq_36722039/article/details/84996668
今日推荐