Shiro 搭建

使用ssm框架,xml和注解组合的方式搭建shiro框架,初学只搭建最简单的框架,提供认证,授权,密码管理等基本用法

一、搭建一个ssm项目,不需要连接数据库,这里用代码写死,可以正常访问即可,在这个项目基础上搭建shiro

二、导入shiro依赖

<!-- shiro 依赖 -->
        <dependency>
        	<groupId>org.apache.shiro</groupId>
        	<artifactId>shiro-all</artifactId>
        	<version>1.2.3</version>
        </dependency>

三、web.xml中加入shiro的过滤

 <!-- shiro安全过滤器 filter-name这个名字的值会在spring的配置中被引用 -->
	  <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>

四、写一个spring的配置文件,根据这个配置文件,完善shiro的搭建工作

<?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>
	
	<!-- 自定义权限认证:类1,shiro的核心类,这个类需要注入两个属性
         属性1:loginService,这是用于登录的服务的具体实现类,由我们自身业务提供;
         属性2:credentialsMatcher,这个属性不可变,具体的引用类由我们自己写,
                写的这个引用类需要继承SimpleCredentialsMatcher这个类,并且实现
                doCredentialsMatch()这个方法
    -->
	<bean id="authRealm" class="com.enjoy.shiro.AuthRealm">
        <!--登录服务:类2--><!--注解注入-->
		<!--<property name="loginService" ref="loginService"></property>-->
		<!-- 自定义的类,需继承其他类,将这个类通过注解方式注入到spring中,在这里被引用 :类3-->
		<property name="credentialsMatcher" ref="passwordMatcher"/>
	</bean>

	<!-- SecurityManager配置,安全管理配置,引用自定义的authRealm -->
    <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 -->
    </bean>
   
    <!-- filter-name这个名字的值来自于web.xml中filter的名字,shiro核心控制器,默认加载其他过滤器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <!--登录页面  -->
        <property name="loginUrl" value="/index"></property>
        <!-- 登录成功后 -->      
        <property name="successUrl" value="/index2"></property>
        <property name="filterChainDefinitions">
            <!-- /**代表下面的多级目录也过滤 -->
            <value>
				/login = anon
				/logout = anon
				/css/** = anon
				/images/** = anon
				/js/** = anon
				/skin/** = anon
				/resource/** = anon
				/** = authc
				/*.* = authc
            </value>
        </property>
    </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>

五、根据第四部的配置文件,将我们自定义的类写好,一共有三个类需要我们实现

(1)登录服务类—loginService,这个类根据自己实际业务写就可以,我这里没查数据库,写死了用户名,只要输入这个用户名就代表查询到该用户,可以获取该用户的详细信息。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.enjoy.domain.User;

@Service
public class LoginService {
	
	@Autowired
	private User user;
	
	public int login(String username,String password) {
		if("zh".equals(username)) {
			return 1;
		}
		return 0;
	}
	
	public User getUser() {
		return user;
	}

}

(2)自定义权限认证类—AuthRealm,继承AuthorizingRealm这个类,重写认证授权方法

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.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import com.enjoy.domain.User;
import com.enjoy.service.LoginService;

public class AuthRealm extends AuthorizingRealm{
	
	@Autowired
	private LoginService loginService;

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
		System.out.println("调用授权方法");
		
		//获取当前用户,拿到用户详细信息
		User user = (User)pc.getPrimaryPrincipal();
		
		//获取授权类,添加授权信息
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		info.addStringPermission("系统首页");
		info.addStringPermission("系统");
		
		return info;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
		System.out.println("调用认证方法");
		//获取token,得到用户名和密码
		UsernamePasswordToken token = (UsernamePasswordToken)arg0;
		String username = token.getUsername();
		String password = new String(token.getPassword());
		int i = loginService.login(username, password);
		//如果用户存在,则返回info,走密码对比,否则返回null,抛出异常
		if(i ==1) {
			User user = loginService.getUser();
			SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),this.getName());
			return info;                        
		}else {
			return null;
		}
	}
}

(3)自定义密码比较算法类—CustomCredentialsMatcher,需要继承SimpleCredentialsMatcher类,重写doCredentialsMatch方法

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.springframework.stereotype.Component;

/**
 * 
 * @author myPC
 *     自定义加密算法
 */
@Component(value="passwordMatcher")
public class CustomCredentialsMatcher extends SimpleCredentialsMatcher{

	@Override
	/*
	 * 参数1:token,用户输入信息
	 * 参数2:info,数据库查出的信息
	 * 返回值:布尔值
	 */
	public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
		//比较用户输入的密码和数据库密码是否一致
		System.out.println("调用自定义密码对比方法");
		//获取用户输入的密码
		char[] password = ((UsernamePasswordToken)token).getPassword();
		String pw = new String(password);
		String md5 = MD5Util.getMD5(pw, ((UsernamePasswordToken)token).getUsername(), 2);
		//获取数据库存的密码
		Object obj = info.getCredentials();
		return equals(md5,obj);
	}

}

以上这三个类,有的是通过xml方式注入到spring中,有的是通过注解注入。需要搞清楚。

附MD5加密工具类

import org.apache.shiro.crypto.hash.Md5Hash;

public class MD5Util {
	
	public static String getMD5(String arg0,String arg1,int arg2) {
		//MD5加密
		//参数1:要加密的字符串,参数2:混淆的字符串,参数3,哈希几次
		Md5Hash hash = new Md5Hash(arg0,arg1,arg2);
		
		return hash.toString();
		
	}

}

六、调用shiro方式进项登录

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

@Controller
@RequestMapping("/")
public class IndexController {
	
	@RequestMapping("login")
	public String toLogin(String username,String password) {
		
		//获得subject
		Subject subject = SecurityUtils.getSubject();
		//创建令牌,传入用户名和密码
		UsernamePasswordToken token = new UsernamePasswordToken(username,password); 
		try {
        //调用subject的login方法,传入令牌,如果没跑出异常,则进入index2方法,否则进入login
			subject.login(token);
		} catch (Exception e) {
			System.out.println("未验证,请登录");
			return "login";
		}
		return "index2";
	}

七、启动项目,输入licalhost:8090/login

输入用户名和密码,zh/123

     

根据右面对应的页面name值为系统首页的有权限,显示标签,name值为系统1的没有授权,不显示

@RequiresPermissions({"系统首页"})
	@RequestMapping("index4")
	public String toIndex4() {
		return "index4";
	}

index4路径需要获得系统首页的授权才能访问。

八、总结。整个访问流程是通过web.xml进行拦截,在spring的配置中多级目录过滤进行授权,系统访问时,调用subject.login()方法,走认证方法,比对完密码后如果正确进行放行,如果在访问时需要权限认证,则在走授权方法,判断是否有权限,有权限就放行。

猜你喜欢

转载自blog.csdn.net/csdnbeyoung/article/details/95869492