shiro一之实例运用

参考:http://hnbcjzj.iteye.com/blog/1706600

简介: Shiro 是一个 Apache Incubator 项目,旨在简化身份验证和授权。是一个很不错的安全框架。 

借用别人写的一个shiro框架的实例来对shiro的应用做下记录。

1.基本概念

首先理解两个概念:认证和授权

我开始接触权限的时候,并没有明确区分认证和授权,把这两个概念混为一团,导致在开始运用shi'ro的时候有些地方没有理解透彻。

认证,简单来说,就是指用户身份是否合法,通俗的理解就是用户是否是登录用户,登录的用户为认证用户,为登录的用户为非认证用户。

授权,一般来说,认证是第一步,用户经过认证以后,只能说明用户是系统的合法用户,但是权限是分级别的,用户身份合法并不代表用户就对所有资源拥有操作权限,要对某一个资源操作,还需要相应的权限管理,这就是授权要就解决的问题。

2.配置

结合DEMO进行说明。

先将shiro引入web.xml

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:applicationContext.xml,classpath:spring-shiro.xml</param-value>
	</context-param>

	<!-- apache 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>*.do</url-pattern>
	</filter-mapping>
	<filter-mapping>
		<filter-name>shiroFilter</filter-name>
		<url-pattern>*.jsp</url-pattern>
	</filter-mapping>

shiro的配置文件是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:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd   
    http://www.springframework.org/schema/util 
    http://www.springframework.org/schema/util/spring-util-3.0.xsd">
	<description>Shiro 配置</description>
	<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="/login.jsp" />
		<property name="unauthorizedUrl" value="/error/noperms.jsp" />
		<property name="filterChainDefinitions">
			<value>
				/login.jsp* = anon
				/login.do* = anon
				/index.jsp*= anon
				/error/noperms.jsp*= anon
				/*.jsp* = authc
				/*.do* = authc
			</value>
		</property>
	</bean>

	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<!--设置自定义realm -->
		<property name="realm" ref="monitorRealm" />
	</bean>

	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

	<!--自定义Realm 继承自AuthorizingRealm -->
	<bean id="monitorRealm" class="com.shiro.service.MonitorRealm"></bean>
	<!-- securityManager -->
	<bean
		class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
		<property name="staticMethod"
			value="org.apache.shiro.SecurityUtils.setSecurityManager" />
		<property name="arguments" ref="securityManager" />
	</bean>

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

</beans>

在这个配置文件中有两个重点要关注的地方:

1)过滤器配置。在里面有两个类型的过滤器配置,anon和authc,anon,要注意的是anon必须配置在authc配置项的前面,否则anon配置项会失效。

Anon:不指定过滤器,不错是这个过滤器是空的,什么都没做,跟没有一样。 
Authc:验证,这些页面必须验证后才能访问,也就是我们说的登录后才能访问。 

简单来讲,anon就是指所有用户(匿名用户)都可以访问的资源,authc是指认证用户(登录用户)才可以访问的资源。
这里还有其他的过滤器,我没用,比如说授权,这个比较重要,但是这个过滤器有个不好的地方,就是要带一个参数,所以如果配在这里就不是很合适,因为每个页面,或是.do的权限不一样,而我们也没法事先知道他需要什么权限。所以这里不配,我们在代码中再授权。这里.do和.jsp后面的*表示参数,比如login.jsp?main这种,是为了匹配这种。好行了,继续往下吧。 

2)自定义realm

realm的作用就是自己来定义认证和授权的业务逻辑。可以灵活的控制权限。这里自定义了一个monitorRealm用来自己写权限业务,这个后面慢慢说明。

3.认证

现在先看第一步认证。

打开登录页面,输入用户名/密码点击提交,就会提交到后台的登录actIon的方法:

	@RequestMapping(params = "main")
	public ModelAndView login(User user,HttpSession session, HttpServletRequest request) {

		ModelAndView modelView = new ModelAndView();
		Subject currentUser = SecurityUtils.getSubject();
		UsernamePasswordToken token = new UsernamePasswordToken(
				user.getUsercode(), EncryptUtils.encryptMD5(user.getPassword()));
		token.setRememberMe(true);
		try {
			currentUser.login(token);
		} catch (AuthenticationException e) {
			modelView.addObject("message", "login errors");
			modelView.setViewName("/login");
			e.printStackTrace();
			
		}
		if(currentUser.isAuthenticated()){
			user.setUserName("张三");
			session.setAttribute("userinfo", user);
			modelView.setViewName("/main");
		}else{
			modelView.addObject("message", "login errors");
			modelView.setViewName("/login");
		}
		return modelView;
	}

这里有两条语句需要说明:

Subject currentUser = SecurityUtils.getSubject() ;

currentUser就是代表当前的用户。 

UsernamePasswordToken token = new UsernamePasswordToken(user.getUsercode(),EncryptUtils.encryptMD5(user.getPassword())); 

token大家叫他令牌,也就相当于一张表格,你要去验证,你就得填个表,里面写好用户名密码,交给公安局的同志给。

currentUser.login(token); 

 这个就是校验token,校验过程会回调realm里面的认证方法:

protected AuthenticationInfo doGetAuthenticationInfo() 

这里就是自己写认证逻辑的地方,看下这里的业务

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authcToken) throws AuthenticationException {
		/* 这里编写认证代码 */
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
//		User user = securityApplication.findby(upToken.getUsername());
		User user = new User();
		user.setUsercode(token.getUsername());
		user.setUserName("admin");
		user.setPassword(EncryptUtils.encryptMD5("admin"));
//		if (user != null) {
		return new SimpleAuthenticationInfo(user.getUserName(),
				user.getPassword(), getName());


	}

是否调用这里是在前面的配置文件中配置的,我们前面spring里配了这个 

/*.jsp* = authc 
/*.do* = authc 


你配了authc过滤器,shiro会自动调currentUser.isAuthenticated()这个方法,没有登录的将被返回 

<property name="unauthorizedUrl" value="/error/noperms.jsp" /> 

配置的页面。

调用这个认证方法后,会对用户的用户名密码进行校验,校验失败跳转到登录页面,校验成功处理登录方法后的逻辑。这里是跳转到main主页。

4.授权

再看第二步,授权

再main页面上点击myjsp,会提交到user.do?myjsp,看下后台的这个方法:

	@RequestMapping(params = "myjsp")
	public String home() {
		Subject currentUser = SecurityUtils.getSubject();
		if(currentUser.isPermitted("user.do?myjsp")){
			return "my";
		}else{
			return "error/noperms";
		}
	}

这里

Subject currentUser = SecurityUtils.getSubject(); 
currentUser.isPermitted("user.do?myjsp"); 

这两行语句的意思是判断当前用户是否有访问user.do?myjsp的权限

调用currentUser.isPermitted("user.do?myjsp");此方法后会回调realm中的授权验证方法

protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals)

看下这里是如何授权的:

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		/* 这里编写授权代码 */
		Set<String> roleNames = new HashSet<String>();
	    Set<String> permissions = new HashSet<String>();
	    roleNames.add("admin");
	    permissions.add("user.do?myjsp");
	    permissions.add("login.do?main");
	    permissions.add("login.do?logout");
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
	    info.setStringPermissions(permissions);
		return info;

	}

这里没有用到数据库,直接将权限硬编码在代码里面,添加admin角色,然后给角色添加权限,当然正常肯定是预先存放在数据库里面,直接从数据库里面查询出来,构造成一个权限对象返回,再与currentUser.isPermitted()中传入的权限参数进行对比,看看用户是否有访问此地址参数的权限,没有权限就返回到没有权限的页面。

5.总结

通过前面的demo流程,可以分析出如下几点:

1)认证的配置一般都是配置再shiro的配置文件,而授权设置比较灵活,一般不直接写在shiro配置文件里面。

2)认证是授权的前提,通过通过了认证,才会用相应的权限管理。

3)认证过程会调用reanlm里面的认证方法doGetAuthenticationInfo(),授权会调用realm里面的授权方法doGetAuthenticationInfo()

一般认证方法只会在登录的时候调用一次,而授权则在需要授权的地方都会调用,会被多次调用。

猜你喜欢

转载自blog.csdn.net/w450093854/article/details/84402160