Bootstrap

Shiro

一、Shiro概述

1、什么是Shiro
  • Apache Shiro 是Java 的一个安全框架。Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE 环境,也可以用在JavaEE 环境。Shiro 可以帮助我们完成:认证、授权、加密、会话管理、与Web 集成、缓存等。
2、为什么要学Shiro
  • shiro将安全认证相关的功能抽取出来组成一个框架,使用shiro就可以非常快速的完成认证、授权等功能的开发,降低系统成本。
  • shiro使用广泛,shiro可以运行在web应用,非web应用,集群分布式应用中越来越多的用户开始使用shiro。
  • java领域中spring security(原名Acegi)也是一个开源的权限管理框架,但是spring security依赖spring运行,而shiro就相对独立,最主要是因为shiro使用简单、灵活,所以现在越来越多的用户选择shiro。
3、基本功能

在这里插入图片描述

  • Authentication:身份认证/登录,验证用户是不是拥有相应的身份

  • Authorization :授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用

    户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用

    户对某个资源是否具有某个权限。

  • Session Manager :会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信

    息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;

  • Cryptography :加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储

  • Web Support :Web支持,可以非常容易的集成到Web 环境

  • Caching :缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率

  • Concurrency :shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能 把权限自动传播过去

  • Testing :提供测试支持

  • Run As :允许一个用户假装为另一个用户(如果他们允许)的身份进行访问

  • Remember Me :记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录

注意:Shiro 不会去维护用户、维护权限;这些需要我们自己去设计/提供;然后通过相应的接口注入给Shiro即可。

4、架构说明

在这里插入图片描述

  • Subject :Subject即主体,外部应用与subject进行交互,subject记录了当前操作用户,将用户的概念理解为当前操作的主体,可能是一个通过浏览器请求的用户,也可能是一个运行的程序。 Subject在shiro中是一个接口,接口中定义了很多认证授相关的方法,外部程序通过subject进行认证授,而subject是通过SecurityManager安全管理器进行认证授权

  • SecurityManager:SecurityManager即安全管理器,对全部的subject进行安全管理,它是shiro的核心,负责对所有的subject进行安全管理。通过SecurityManager可以完成subject的认证、授权等,实质上SecurityManager是通过Authenticator进行认证,通过Authorizer进行授权,通过SessionManager进行会话管理等。SecurityManager是一个接口,继承了Authenticator,Authorizer, SessionManager这三个接口。

  • Authenticator :Authenticator即认证器,对用户身份进行认证,Authenticator是一个接口,shiro提供ModularRealmAuthenticator实现类,通过ModularRealmAuthenticator基本上可以满足大多数需求,也可以自定义认证器。

  • Authorizer :Authorizer即授权器,用户通过认证器认证通过,在访问功能时需要通过授权器判断用户是否有此功能的操作权限。

  • realm :Realm即领域,相当于datasource数据源,securityManager进行安全认证需要通过Realm获取用户权限数据,比如:如果用户身份数据在数据库那么realm就需要从数据库获取用户身份信息。

    注:不要把realm理解成只是从数据源取数据,在realm中还有认证授权校验的相关的代码。

  • sessionManager :sessionManager即会话管理,shiro框架定义了一套会话管理,它不依赖web容器的session,所以shiro可以使用在非web应用上,也可以将分布式应用的会话集中在一点管理,此特性可使它实现单点登录。

  • SessionDAO :SessionDAO即会话dao,是对session会话操作的一套接口,比如要将session存储到数据库,可以通过jdbc将会话存储到数据库。

  • CacheManager :CacheManager即缓存管理,将用户权限数据存储在缓存,这样可以提高性能。

  • Cryptography : Cryptography即密码管理,shiro提供了一套加密/解密的组件,方便开发。比如提供常用的散列、加/解密等功能。

二、Shiro.ini文件

1、Shiro.ini文件说明
  • ini(InitializationFile) 初始文件.Window系统文件扩展名
  • Shiro使用时可以连接数据库,也可以不连接数据库,如果不连接数据库,可以在shiro.ini中配置静态数据
2、Shrio.ini文件的组成部分
  • [main] :定义全局变量

    1 内置securityManager对象

    2 操作内置对象时,在[main]里面写东西

    [main]
    securityManager.属性=值     
    myobj=com.itan.lei    			<bean id=myobj class=” com.itan.lei”>
    securityManager.对象属性=$myobj   <bean id=” securityManager” class=””>
                                     <property name=” 对象属性” ref=” myobj”>
    
  • [users] :定义用户名和密码

    [users]
    # 定义用户名为zhangsan 密码为zs
    zhangsan=zs
    # 定义用户名lisi密码为lisi同时具有role1和role2两个角色
    lisi=lisi,role1,role2
    
  • [roles]:定义角色

    [roles]
    role1=权限名1,权限名2 
    role2=权限3,权限4
    #如
    [roles]
    role1=user:query,user:add,user:update,user:delete,user:export
    role2=user:query,user:add
    
  • [urls] : 定义哪些内置urls生效.在web应用时使用

    [urls]
    #url地址=内置filter或自定义filter
    # 访问时出现/login的url必须去认证.支持authc对应的Filter 
    /login=authc
    # 任意的url都不需要进行认证等功能.
    /** = anon
    # 所有的内容都必须保证用户已经登录.
    /**=user
    # url abc 访问时必须保证用户具有role1和role2角色.
    /abc=roles[“role1,role2”]
    #authc   代表必须认证之后才能访问的路径
    #anon    任意的url都不需要进行认证等功能
    #user     所有的内容都必须保证用户已经登录.
    #logout   注销
    

    在这里插入图片描述

三、Shiro实现认证_ini

1、基本概念
  • 身份验证:即在应用中谁能证明他就是他本人。一般提供如他们的身份ID 一些标识信息来表明他就是他本人,如提供身份证,用户名/密码来证明。在 shiro 中,用户需要提供principals (身份)和credentials(证明)给shiro,从而应用能验证用户身份

  • principals :身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。一个主体可以有多个principals,但只有一个Primary principals,一般是用户名/密码/手机号。

  • credentials :证明/凭证,即只有主体知道的安全值,如密码/数字证书等。最常见的principals和credentials组合就是用户名/密码了。接下来先进行一个基本的身份认证。

2、认证流程

在这里插入图片描述

3、使用shiro的ini文件完成认证功能
  • 创建项目(jar)并引入shiro-core的依赖

    <dependencies>
    	<!-- shiro核心依赖 -->
    	<dependency>
    		<groupId>org.apache.shiro</groupId>
    		<artifactId>shiro-core</artifactId>
    		<version>1.4.1</version>
    	</dependency>
    	<!-- 日志依赖 -->
    	<dependency>
    		<groupId>org.slf4j</groupId>
    		<artifactId>slf4j-simple</artifactId>
    		<version>1.7.21</version>
    		<scope>compile</scope>
    	</dependency>
    	<dependency>
    		<groupId>org.slf4j</groupId>
    		<artifactId>jcl-over-slf4j</artifactId>
    		<version>1.7.21</version>
    		<scope>compile</scope>
    	</dependency>
    </dependencies>
    
  • 创建shiro.ini

    #配置用户
    [users]
    zhangsan=123456
    lisi=123456
    
  • 创建Test类测试

    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.config.IniSecurityManagerFactory;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.subject.Subject;
    import org.apache.shiro.util.Factory;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * shiro的认证使用shiro.ini
     * @author admin
     *
     */
    public class Test {
    	// 日志输出工具
    	private static final transient Logger log = LoggerFactory.getLogger(Test.class);
    	public static void main(String[] args) {
    		String username="zhangsan";
    		String password="123456";
    		log.info("My First Apache Shiro Application");
    		//1、创建安全管理器的工厂对象 org.apache.shiro.mgt.SecurityManager
    		Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro.ini");
    		//2、使用工厂创建安全管理器
    		SecurityManager securityManager = factory.getInstance();
    		//3、把当前的安全管理器绑定当前线程
    		SecurityUtils.setSecurityManager(securityManager);
    		//4、使用SecurityUtils.getSubject()得到主体对象
    		Subject subject = SecurityUtils.getSubject();
    		//5、封装用户名和密码
    		AuthenticationToken token=new UsernamePasswordToken(username,password);
    		//6、得到认证
    		try {
    			subject.login(token);
    			System.out.println("认证通过");
    		} catch (AuthenticationException e) {
    			System.out.println("用户名或密码不正确");
    		} 
    	}
    }
    

四、shiro.ini实现授权

1、概述
  • 授权,也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、角色(Role)。

  • 前提:必须先认证通过之后有授权之说

2、关键对象介绍
  1. 主体

    即访问应用的用户,在Shiro中使用Subject代表该用户。用户只有授权后才允许访问相应的资源。

  2. 资源

    在应用中用户可以访问的任何东西,比如访问JSP 页面、查看/编辑某些数据、访问某个业务方法、打印文本等等都是资源。用户只要授权后才能访问。

  3. 权限

    安全策略中的原子授权单位,通过权限我们可以表示在应用中用户有没有操作某个资源的权力。即权限表示在应用中用户能不能访问某个资源,如:访问用户列表页面查看/新增/修改/删除用户数据(即很多时候都是CRUD(增查改删)式权限控制)打印文档等等

  4. 角色

    角色代表了操作集合,可以理解为权限的集合,一般情况下我们会赋予用户角色而不是权限,即这样用户可以拥有一组权限,赋予权限时比较方便。典型的如:项目经理、技术总监、CTO、开发工程师等都是角色,不同的角色拥有一组不同的权限。

3、授权流程

在这里插入图片描述

  • subject.hasRole(“”):判断是否有角色。
  • subject.hashRoles(List):分别判断用户是否具有List中每个内容。
  • subject.hasAllRoles(Collection):返回boolean,要求参数中所有角色用户都需要具有。
  • subject.isPermitted(“”):判断是否具有权限。
  • subject.logout():退出的方法
4、修改shiro.ini
#配置用户
[users]
zhangsan=123456,role1
lisi=123456,role2
wangwu=123456,role3
zhaoliu=123456,role2,role3

#声明角色
[roles]
role1=user:query,user:add,user:update,user:delete,user:export
role2=user:query,user:add
role3=user:query,user:export
5、测试
import java.util.Arrays;
import java.util.List;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * shiro的认证授权使用shiro.ini
 * @author admin
 *
 */
public class Test {
	// 日志输出工具
	private static final transient Logger log = LoggerFactory.getLogger(Test.class);
	public static void main(String[] args) {
		String username="zhangsan";
		String password="123456";
		log.info("My First Apache Shiro Application");
		//1、创建安全管理器的工厂对象
		Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro.ini");
		//2、使用工厂创建安全管理器
		SecurityManager securityManager = factory.getInstance();
		//3、把当前的安全管理器绑定当前线程
		SecurityUtils.setSecurityManager(securityManager);
		//4、使用SecurityUtils.getSubject()得到主体对象
		Subject subject = SecurityUtils.getSubject();
		//5、封装用户名和密码
		AuthenticationToken token=new UsernamePasswordToken(username,password);
		//6、得到认证
		try {
			subject.login(token);
			System.out.println("认证通过");
		} catch (AuthenticationException e) {
			System.out.println("用户名或密码不正确");
		}
      
      	/**
		 * 角色判断
		 */
		//7、判断用户是否认证通过
		boolean flag=subject.isAuthenticated();
		System.out.println("是否通过认证:"+flag);
		//8、判断用户是否具有某个角色
		boolean hasRole = subject.hasRole("role1");
		System.out.println("是否具有role1的角色:"+hasRole);
		//9、分别判断用户是否具有集合里面的角色,返回数据
		List<String> roleIdentifiers=Arrays.asList("role1","role2","role3");
		boolean[] hasRoles = subject.hasRoles(roleIdentifiers);
		for (boolean b : hasRoles) {
			System.out.println(b);
		}
		//10、判断用户是否具有roleIdentifiers集合里面的所有角色
		boolean hasAllRoles = subject.hasAllRoles(roleIdentifiers);
		System.out.println(hasAllRoles);
      	/**
		 *  权限判断
		 */
		//11、当前用户是否具有某个权限
		boolean permitted = subject.isPermitted("user:query");
		System.out.println("判断当前用户是否有user:query的权限  "+permitted);
		//12、分别判断当前用户是否具有权限,返回数组
		boolean[] permitted2 = subject.isPermitted("user:query","user:add","user:export");
		for (boolean b : permitted2) {
			System.out.println(b);
		}
		//13、判断用户是否具有所有的权限
		boolean permittedAll = subject.isPermittedAll("user:query","user:add","user:export");
		System.out.println(permittedAll);
	}
}

五、自定义Realm实现认证

1、使用自定义Realm的原因
  • Shiro默认使用自带的IniRealmIniRealmini配置文件中读取用户的信息,大部分情况下需要从系统的数据库中读取用户信息,所以需要自定义realm
2、Realm接口
  • 最基础的是Realm接口,CachingRealm负责缓存处理,AuthenticationRealm负责认证,AuthorizingRealm负责授权,通常自定义的realm继承AuthorizingRealm
3、实现步骤
  • 创建项目

  • 创建User实体类,生成有参构造和get、set方法

    private Integer id;
    private String username;
    private String password;
    private Date createTime;
    public User(Integer id, String username, String password, Date createTime) {
        super();
        this.id = id;
        this.username = username;
        this.password = password;
        this.createTime = createTime;
    }
    
  • 创建UserService接口

    /**
     * 根据用户名查询用户对象
     */
    public User queryUserByUserName(String username);
    
  • 创建UserServiceImpl实现接口,模拟数据库

    public class UserServiceImpl implements UserService{
    	@Override
    	public User queryUserByUserName(String username) {
    		User user=null;
    		switch (username) {
    		case "zhangsan":
    			user=new User(1,"zhangsan","123456",new Date());
    			break;
    		case "lisi":
    			user=new User(2,"lisi","123456",new Date());
    		break;
    		case "wangwu":
    			user=new User(1,"wangwu","123456",new Date());
    		break;
    		}
    		return user;
    	}
    }
    
  • 创建UserRealm继承AuthenticatingRealm类

    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.realm.AuthenticatingRealm;
    import com.itan.entity.User;
    import com.itan.service.UserService;
    import com.itan.service.impl.UserServiceImpl;
    
    public class UserRealm extends AuthenticatingRealm{
    	private UserService userService=new UserServiceImpl();
    	/**
    	 * 认证
    	 */
    	@Override
    	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    		//获取用户名
    		String username=token.getPrincipal().toString();
    		/**
    		 * 以前登录的逻辑是把用户和密码全部发到数据库去匹配
    		 * 在shiro里面是先根据用户名把用户对象查询出来,再来做密码匹配
    		 */
    		User user = this.userService.queryUserByUserName(username);
    		//判断用户是否存在
    		if(null!=user) {
    			/**
    			 * 参数说明:
    			 * 参数1:可以传任何对象
    			 * 参数2:从数据库里面查询出来的密码
    			 * 参数3:当前类名
    			 */
    			SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),this.getName());
    			return info;
    		}else {
    			//用户不存在,shiro会抛出UnknowAccoutException异常
    			return null;
    		}
    	}
    }
    
  • 测试

    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.config.IniSecurityManagerFactory;
    import org.apache.shiro.mgt.DefaultSecurityManager;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.subject.Subject;
    import org.apache.shiro.util.Factory;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import com.itan.realm.UserRealm;
    
    public class Test {
    	// 日志输出工具
    	private static final transient Logger log = LoggerFactory.getLogger(Test.class);
    	public static void main(String[] args) {
    		String username="zhangsan";
    		String password="12345";
    		log.info("My First Apache Shiro Application");
    		//1、创建安全管理器的工厂对象
    		Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro.ini");
    		//2、使用工厂创建安全管理器
    		DefaultSecurityManager securityManager = (DefaultSecurityManager)factory.getInstance();
    		//3、创建UserRealm
    		UserRealm realm=new UserRealm();
    		//4、给securityManager注入userRealm
    		securityManager.setRealm(realm);
    		//5、把当前的安全管理器绑定当前线程
    		SecurityUtils.setSecurityManager(securityManager);
    		//6、使用SecurityUtils.getSubject()得到主体对象
    		Subject subject = SecurityUtils.getSubject();
    		//7、封装用户名和密码
    		AuthenticationToken token=new UsernamePasswordToken(username,password);
    		//8、得到认证
    		try {
    			subject.login(token);
    			System.out.println("认证通过");
    			User user = (User)subject.getPrincipal();
    			System.out.println(user);
    		} catch (AuthenticationException e) {
    			System.out.println("用户名或密码不正确");
    		}
    	}
    }
    

六、自定义Realm实现授权

1、复制五中创建的项目
2、创建ActiverUser实体类
public class ActiverUser {
	private User user;
	private List<String> roles;
	private List<String> permissions;
	public ActiverUser(User user, List<String> roles, List<String> permissions) {
		super();
		this.user = user;
		this.roles = roles;
		this.permissions = permissions;
	}
	public ActiverUser() {
	}
  	//省略get、set方法
}
3、创建RoleService角色接口
public interface RoleService {
	/**
	  * 根据用户名查询用户拥有的角色
	 * @param username
	 * @return
	 */
	public List<String> queryRoleByUserName(String username);
}
4、创建RoleServiceImpl实现类
public class RoleServiceImpl implements RoleService{
	@Override
	public List<String> queryRoleByUserName(String username) {
      	//模拟从数据库中获取当前用户所有角色
		return Arrays.asList("role1","role2","role3");
	}
}
5、创建PermissionService权限接口
public interface PermissionService {
	/**
	  * 根据用户名查询用户拥有的权限
	 * @param username
	 * @return
	 */
	public List<String> queryPermissionByUserName(String username);
}
6、创建PermissionServiceImpl实现类
public class PermissionServiceImpl implements PermissionService {
	@Override
	public List<String> queryPermissionByUserName(String username) {
      	//模拟从数据库中获取当前用户所有权限
		return Arrays.asList("user:query","user:add","uer:del","user:upd");
	}
}
7、修改UserRealm继承AuthorizingRealm类
public class UserRealm extends AuthorizingRealm{
	private UserService userService=new UserServiceImpl();
	private RoleService roleService=new RoleServiceImpl();
	private PermissionService permissionService=new PermissionServiceImpl();
	/**
	 * 认证
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		//获取用户名
		String username=token.getPrincipal().toString();
		/**
		  * 以前登录的逻辑是把用户和密码全部发到数据库去匹配
		  * 在shiro里面是先根据用户名把用户对象查询出来,再来做密码匹配
		 */
		User user = this.userService.queryUserByUserName(username);
		//判断用户是否存在
		if(null!=user) {
			//查询用户有哪些角色
			List<String> roles=roleService.queryRoleByUserName(user.getUsername());
			//查询用户有哪些权限
			List<String> permissions=permissionService.queryPermissionByUserName(user.getUsername());
			ActiverUser activerUser=new ActiverUser(user,roles,permissions);
			/**
			 * 参数说明:
			 * 参数1:可以传任何对象
			 * 参数2:从数据库里面查询出来的密码
			 * 参数3:当前类名
			 */
			SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(activerUser,user.getPassword(),this.getName());
			return info;
		}else {
			//用户不存在,shiro会抛出UnknowAccoutException异常
			return null;
		}
	}
	/**
	 * 授权
	 * 参数说明
	 * 
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		ActiverUser activerUser = (ActiverUser) principals.getPrimaryPrincipal();
		SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
		//添加角色
		Collection<String> roles=activerUser.getRoles();
		if(null!=roles&&roles.size()>0) {
			info.addRoles(roles);
		}
		//添加权限
		Collection<String> permissions=activerUser.getPermissions();
		if(null!=permissions&&permissions.size()>0) {
			info.addStringPermissions(permissions);
		}
		//若是超级管理员,就赋予所有权限
//		if(activerUser.getUser().getType()==0) {
//			info.addStringPermission("*:*");
//		}
		return info;
	}
}
8、测试类
public class Test {
	// 日志输出工具
	private static final transient Logger log = LoggerFactory.getLogger(Test.class);
	public static void main(String[] args) {
		String username="zhangsan";
		String password="123456";
		log.info("My First Apache Shiro Application");
		//1、创建安全管理器的工厂对象
		Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro.ini");
		//2、使用工厂创建安全管理器
		DefaultSecurityManager securityManager = (DefaultSecurityManager)factory.getInstance();
		//3、创建UserRealm
		UserRealm realm=new UserRealm();
		//4、给securityManager注入userRealm
		securityManager.setRealm(realm);
		//5、把当前的安全管理器绑定当前线程
		SecurityUtils.setSecurityManager(securityManager);
		//6、使用SecurityUtils.getSubject()得到主体对象
		Subject subject = SecurityUtils.getSubject();
		//7、封装用户名和密码
		AuthenticationToken token=new UsernamePasswordToken(username,password);
		//8、得到认证
		try {
			subject.login(token);
			System.out.println("认证通过");
		} catch (AuthenticationException e) {
			System.out.println("用户名或密码不正确");
		}
		//9、判断用户是否具有某个角色
		boolean hasRole = subject.hasRole("role1");
		System.out.println("是否具有role1角色:"+hasRole);
		//10、判断用户是否有权限
		boolean permitted = subject.isPermitted("user:query");
		System.out.println("是否有query权限:"+permitted);
	}
}

七、散列算法+凭证配置

1、散列算法概述
  • 散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据,常见的散列算法如MD5、SHA等。一般进行散列时最好提供一个salt(盐),比如加密密码“admin”,产生的散列值是“21232f297a57a5a743894a0e4a801fc3”,可以到一 些md5 解密网站很容易的通过散列值得到密码“admin”,即如果直接对密码进行散列相对来说破解更容易,此时我们可以加一些只有系统知道的干扰数据,如用户名和ID(即盐); 这样散列的对象是“密码+用户名+ID”,这样生成的散列值相对来说更难破解。
2、MD5算法(Shiro)
//shiro提供了现成的加密类 Md5Hash
public static void main(String[] args) {
    String source="123456";
    Md5Hash hash1=new Md5Hash(source);
    System.out.println("使用MD5加密后的结果:"+hash1.toString());
    Md5Hash hash2=new Md5Hash(source, "北京武汉"); 
    System.out.println("使用MD5加密并加盐后的结果:"+hash2.toString());
    Md5Hash hash3=new Md5Hash(source, "北京武汉", 2);
    System.out.println("使用MD5加密加盐并散列两次后的结果:"+hash3.toString());
}
3、封装MD5工具类
public class MD5Utils{
     /**
       * 对密码加密 md5
       * @param source  要加密的明文
       * @param salt  盐
       * @param hashIterations  散列次数
       * @return
       */
	public static String md5(String source, Object salt, Integer hashIterations) {
		return new Md5Hash(source, salt, hashIterations).toString();
	}
}
4、凭证配置
  • 方式1:在UserRealm的空参构造中配置

    public UserRealm() {
        //注入凭证匹配器
        HashedCredentialsMatcher credentialsMatcher=new HashedCredentialsMatcher();
        //指定加密算法
        credentialsMatcher.setHashAlgorithmName("md5");
        //指定散列次数
        credentialsMatcher.setHashIterations(2);
        setCredentialsMatcher(credentialsMatcher);
    }
    
  • 方式2:在ini文件中配置

    [main]
    #创建凭证匹配器
    credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
    #指定加密算法
    credentialsMatcher.hashAlgorithmName=md5
    #指定散列次数
    credentialsMatcher.hashIterations=2
    #创建userRealm对象
    userRealm=com.itan.realm.UserRealm
    #给userRealm注入凭证匹配器
    userRealm.credentialsMatcher=$credentialsMatcher
    #把当前对象给安全管理器
    securityManager.realm=$userRealm
    
  • 方式3:在测试类中

    public class Test {
    	// 日志输出工具
    	private static final transient Logger log = LoggerFactory.getLogger(Test.class);
    	public static void main(String[] args) {
    		String username="zhangsan";
    		String password="123456";
    		log.info("My First Apache Shiro Application");
    		//1、创建安全管理器的工厂对象
    		Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro.ini");
    		//2、使用工厂创建安全管理器
    		DefaultSecurityManager securityManager = (DefaultSecurityManager)factory.getInstance();
    		//3、创建UserRealm
    		UserRealm realm=new UserRealm();
          	/**
          	 *凭证的认证
          	 */
    		//注入凭证匹配器
    		HashedCredentialsMatcher credentialsMatcher=new HashedCredentialsMatcher();
    		//指定加密算法
    		credentialsMatcher.setHashAlgorithmName("md5");
    		//指定散列次数
    		credentialsMatcher.setHashIterations(2);
    		realm.setCredentialsMatcher(credentialsMatcher);
    		//4、给securityManager注入userRealm
    		securityManager.setRealm(realm);
    		//5、把当前的安全管理器绑定当前线程
    		SecurityUtils.setSecurityManager(securityManager);
    		//6、使用SecurityUtils.getSubject()得到主体对象
    		Subject subject = SecurityUtils.getSubject();
    		//7、封装用户名和密码
    		AuthenticationToken token=new UsernamePasswordToken(username,password);
    		//8、得到认证
    		try {
    			subject.login(token);
    			System.out.println("认证通过");
    		} catch (AuthenticationException e) {
    			System.out.println("用户名或密码不正确");
    		}
    		//9、判断用户是否具有某个角色
    		boolean hasRole = subject.hasRole("role1");
    		System.out.println("是否具有role1角色:"+hasRole);
    		//10、判断用户是否有权限
    		boolean permitted = subject.isPermitted("user:query");
    		System.out.println("是否有query权限:"+permitted);
    	}
    }
    
5、凭证的认证修改
  • 复制上一个项目

  • 修改UserServiceImpl

    public class UserServiceImpl implements UserService{
    	@Override
    	public User queryUserByUserName(String username) {
    		User user=null;
    		switch (username) {
    		case "zhangsan":
    			user=new User(1,"zhangsan","b4f48723743cc5bfa7c1716296703ce1",new Date());
    			break;
    		case "lisi":
    			user=new User(2,"lisi","b4f48723743cc5bfa7c1716296703ce1",new Date());
    		break;
    		case "wangwu":
    			user=new User(1,"wangwu","b4f48723743cc5bfa7c1716296703ce1",new Date());
    		break;
    		}
    		return user;
    	}
    }
    
  • 修改UserRealm

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
      //获取用户名
      String username=token.getPrincipal().toString();
      /**
       * 以前登录的逻辑是把用户和密码全部发到数据库去匹配
       * 在shiro里面是先根据用户名把用户对象查询出来,再来做密码匹配
       */
      User user = this.userService.queryUserByUserName(username);
      //判断用户是否存在
      if(null!=user) {
        //查询用户有哪些角色
        List<String> roles=roleService.queryRoleByUserName(user.getUsername());
        //查询用户有哪些权限
        List<String> permissions=permissionService.queryPermissionByUserName(user.getUsername());
        ActiverUser activerUser=new ActiverUser(user,roles,permissions);
        /**
         * 参数说明:
         * 参数1:可以传任何对象
         * 参数2:从数据库里面查询出来散列之后的密码
         * 参数3:盐
         * 参数4:当前类名
         */
        ByteSource credentialsSalt=ByteSource.Util.bytes("北京武汉");
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(activerUser,user.getPassword(),credentialsSalt,this.getName());
        return info;
      }else {
        //用户不存在,shiro会抛出UnknowAccoutException异常
        return null;
      }
    }
    
  • 使用方式三做测试

八、ssm+shiro+Realm实现集成

1、数据表结构

在这里插入图片描述

2、搭建ssm的环境
1、创建一个maven项目
  • 修改Java Build Path中的JRE System Library—>Edit—>选择Workspace default JRE—>finish
2、修改pom.xml
<!-- 声明版本控制 -->
<properties>
    <servlet.version>3.1.0</servlet.version>
    <jsp.version>2.3.1</jsp.version>
    <spring.version>4.3.24.RELEASE</spring.version>
    <mybatis.version>3.5.1</mybatis.version>
    <mybatis.spring.version>2.0.1</mybatis.spring.version>
    <mysql.version>5.1.47</mysql.version>
    <pagehelper.version>5.1.10</pagehelper.version>
    <druid.version>1.1.19</druid.version>
    <log4j.version>1.2.17</log4j.version>
    <slf4j.version>1.7.26</slf4j.version>
    <jackson.version>2.9.9</jackson.version>
    <shiro.version>1.4.1</shiro.version>
</properties>
<dependencies>
    <!--servlet -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>${servlet.version}</version>
        <scope>provided</scope>
    </dependency>
    <!-- javax.servlet.jsp -->
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>javax.servlet.jsp-api</artifactId>
        <version>${jsp.version}</version>
        <scope>provided</scope>
    </dependency>
    <!--spring-core -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-oxm</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>${mybatis.version}</version>
    </dependency>
    <!-- mybatis-spring -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>${mybatis.spring.version}</version>
    </dependency>
    <!-- mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.version}</version>
    </dependency>
    <!-- pagehelper -->
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper</artifactId>
        <version>${pagehelper.version}</version>
    </dependency>
    <!-- druid -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>${druid.version}</version>
    </dependency>
    <!-- log4j -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>${log4j.version}</version>
    </dependency>
    <!-- slf4j-api -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>${slf4j.version}</version>
    </dependency>
    <!-- jackson-core -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>${jackson.version}</version>
    </dependency>
    <!-- 引入shiro的包 -->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>${shiro.version}</version>
    </dependency>
</dependencies>
<build>
  	<!--打包文件名-->
    <finalName>ssm_shiro</finalName>
    <plugins>
        <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <!-- 配置urlencoding -->
                <uriEncoding>UTF-8</uriEncoding>
                <!-- 配置端口 -->
                <port>8080</port>
                <!-- 配置访问路径 -->
                <path>/ssm_shiro</path>
            </configuration>
        </plugin>
    </plugins>
</build>
2、创建包
  • entity、service、utils、impl、mapper、controller、realm
3、创建db.properties(druid的)
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/shiro?useUnicode=true&characterEncoding=utf8&useSSL=true
user=root
password=123456
#maxActive 最大的连接数
maxActive=20
#initialSize 初始化连接的个数
initialSize=1
#maxWait 最大等待时间
maxWait=60000
#minIdle 最小活跃连接
minIdle=1
filters=stat,log4j,wall
4、创建log4j.properties
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
6、创建application-dao.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:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="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.xsd">
	<!-- 解析配置文件 -->
	<context:property-placeholder location="classpath:db.properties" system-properties-mode="FALLBACK"/>	
	<!-- 声明数据源 -->
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
		<property name="driverClassName" value="${driver}"/>
		<property name="url" value="${url}"/>
		<property name="username" value="${user}"/>
		<property name="password" value="${password}"/>
		<property name="maxActive" value="${maxActive}"/>
		<property name="initialSize" value="${initialSize}"/>
		<property name="maxWait" value="${maxWait}"/>
		<property name="minIdle" value="${minIdle}"/>
		<property name="filters" value="${filters}"/>
	</bean>
	<!-- 创建mybatis的configuration对象 -->
	<bean id="configuration" class="org.apache.ibatis.session.Configuration">
		<!-- 输出sql语句 -->
		<property name="logImpl" value="org.apache.ibatis.logging.stdout.StdOutImpl"/>
	</bean>
	<!-- 创建sqlSessionFactory -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<!-- 注入数据源 -->
		<property name="dataSource" ref="dataSource"/>
		<!-- 注入mybatis配置类 -->
		<property name="configuration" ref="configuration"/>
		<!-- 扫描mapper.xml -->
		<property name="mapperLocations">
			<array>
				<value>classpath:mapper/*Mapper.xml</value>
			</array>
		</property>
		<!-- 配置分页插件 -->
		<property name="plugins">
			<array>
				<bean class="com.github.pagehelper.PageInterceptor"></bean>
			</array>
		</property>
	</bean>
	<!-- 配置mapper接口的扫描 -->
	<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.itan.mapper"/>
		<!--方式二-->
		<!-- <property name="basePackage">
			<value>
				com.itan.mapper
				com.softeem.mapper
			</value>
		</property> -->
		<!-- 注入SqlSessionFactory -->
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
	</bean>
</beans>
7、创建application-service.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:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="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.xsd
	http://www.springframework.org/schema/aop 
	http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
	http://www.springframework.org/schema/tx 
	http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
	<!-- 扫描service包 -->
	<context:component-scan base-package="com.itan.service.impl"></context:component-scan>
	<!-- 配置事务管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<!-- 注入数据源 -->
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 配置事务的传播特性 -->
	<tx:advice id="advice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="add*" propagation="REQUIRED"/>
			<tx:method name="save*" propagation="REQUIRED"/>
			<tx:method name="insert*" propagation="REQUIRED"/>
			<tx:method name="update*" propagation="REQUIRED"/>
			<tx:method name="del*" propagation="REQUIRED"/>
			<tx:method name="reset*" propagation="REQUIRED"/>
			<tx:method name="change*" propagation="REQUIRED"/>
			<tx:method name="*" read-only="true"/>
		</tx:attributes>
	</tx:advice>
	<!-- 配置aop -->
	<aop:config>
		<aop:pointcut expression="execution(* com.itan.service.impl.*.*(..))" id="ponint"/>
		<aop:advisor advice-ref="advice" pointcut-ref="ponint"/>
	</aop:config>
</beans>
8、创建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">
	<import resource="classpath:application-dao.xml"/>
	<import resource="classpath:application-service.xml"/>
	<import resource="classpath:application-shiro.xml"/>
</beans>
9、创建springmvc.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.3.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.3.xsd">
	<!-- 扫描controller -->
	<context:component-scan base-package="com.itan.controller"></context:component-scan>
	<!-- 配置适配器和映射器 -->
	<mvc:annotation-driven></mvc:annotation-driven>
	<!-- 配置视图解析器 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<!-- 前缀 -->
		<property name="prefix" value="/WEB-INF/view/"></property>
		<!-- 后缀 -->
		<property name="suffix" value=".jsp"></property>
	</bean>
	<!-- 配置静态资源放行 -->
	<mvc:default-servlet-handler/>
</beans>
10、配置web.xml
<!-- 配置编码过滤器 开始 -->
<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <servlet-name>springmvc</servlet-name>
</filter-mapping>
<!-- 配置编码过滤器 结束 -->

<!-- 配置spring的监听器加载 applicationContext.xml开始 -->
<listener>
  	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:applicationContext.xml</param-value>
</context-param>
<!-- 配置spring的监听器加载 applicationContext.xml结束 -->

<!-- 配置前端控制器开始 -->
<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 注入springmvc.xml -->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:springmvc.xml</param-value>
    </init-param>
    <!-- 启动创建 -->
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>*.action</url-pattern>
</servlet-mapping>
<!-- 配置前端控制器结束 -->
3、集成shiro
1、生成实体类
  • User、Permission、Role
2、生成Mapper类
  • UserMapper、PermissionMapper、RoleMapper
3、生成Mapper.xml文件
  • UserMapper.xml、PermissionMapper.xml、RoleMapper.xml
4、在utils包下新建ActivierUser类
public class ActivierUser {
	private User user;
	private List<String> roles;
	private List<String> permissions;
  	public ActivierUser(User user, List<String> roles, List<String> permissions) {
		super();
		this.user = user;
		this.roles = roles;
		this.permissions = permissions;
	}
  	//省略set、get
}
5、创建UserRealm(realm包中)
public class UserRealm extends AuthorizingRealm {
	/**
	 * 认证
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		return null;
	}
	/**
	 * 授权
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		return null;
	}
}

6、创建application-shrio.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:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="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.xsd">
	<!-- 声明凭证匹配器 -->
	<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
		<!--指定加密算法-->
		<property name="hashAlgorithmName" value="md5"></property>
		<!--设置散列次数-->
		<property name="hashIterations" value="2"></property>
	</bean>
	<!-- 声明userRealm -->
	<bean id="userRealm" class="com.itan.realm.UserRealm">
		<!-- 注入凭证匹配器 -->
		<property name="credentialsMatcher" ref="credentialsMatcher"></property>
	</bean>
	<!-- 配置securityManager -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<!-- 注入realm -->
		<property name="realm" ref="userRealm"></property>
	</bean>
	<!-- 配置shiro的过滤器,这里的id必须和web.xml里面的配置一样 -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<!-- 注入安全管理器 -->
		<property name="securityManager" ref="securityManager"></property>
		<!-- 注入未登录的跳转页面,默认是webapp/login.jsp -->
		<property name="loginUrl" value="/index.jsp"></property>
		<!-- 注入未授权的访问页面 -->
		<property name="unauthorizedUrl" value="/unauthorized.jsp"></property>
		<!-- 配置过滤器链 -->
		<property name="filterChainDefinitions">
			<value>
				<!-- 放行index.jsp -->
				/index.jsp*=anon
				<!-- 放行跳转到登录页面的路径 -->
				/login/toLogin*=anon
				<!-- 放行登录的请求 -->
				/login/login*=anon
				<!-- 设置退出的路径 -->
				/login/logout*=logout
				<!-- 设置其他路径全部拦截 -->
				/**=authc
			</value>
		</property>
	</bean>
</beans>
7、在applicationContext.xml中引入shiro配置文件
<!--引入shiro配置文件-->
<import resource="classpath:application-shiro.xml"/>
8、在web.xml中加入shiro配置
<!-- 配置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>
  <init-param>
    <!-- 这里的shiroFilter必须和application-shiro.xml中的ShiroFilterFactoryBean的id一致 -->
    <param-name>targetBeanName</param-name>
    <param-value>shiroFilter</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>shiroFilter</filter-name>
  <servlet-name>springmvc</servlet-name>  	
</filter-mapping>
<!-- 配置shiro的集成结束 -->
4、完成用户权限的开发
1、创建UserService
public interface UserService {
	/**
	 * 根据用户名查询用户对象
	 * @param username
	 * @return
	 */
	public User queryUserByUserName(String username);
}
2、创建UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
	@Autowired
	private UserMapper userMapper;
	@Override
	public User queryUserByUserName(String username) {
		return userMapper.queryUserByUserName(username);
	}
}
3、修改UserMapper
public interface UserMapper {
	/**
	 * 根据用户名查询用户对象
	 * @param username
	 * @return
	 */
   User queryUserByUserName(@Param("username")String username);
}
4、修改UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itan.mapper.UserMapper">
	<!-- 根据用户名查询用户 -->
	<select id="queryUserByUserName" resultType="com.itan.entity.User" parameterType="string">
		select * from user where username=#{username}
	</select>
</mapper>
5、创建RoleService
public interface RoleService {
	/**
	 * 根据用户ID查询角色
	 * @param userId
	 * @return
	 */
	public List<String> queryUserByUserId(Integer userId);
}
6、创建RoleServiceImpl
@Service
public class RoleServiceImpl implements RoleService {
	@Autowired
	private RoleMapper roleMapper;
	@Override
	public List<String> queryUserByUserId(Integer userId) {
		List<Role> list = roleMapper.queryRolesByUserId(userId);
		List<String> roles=new ArrayList<String>();
		for (Role role : list) {
			roles.add(role.getRolename());
		}
		return roles;
	}
}
7、修改RoleMapper
public interface RoleMapper {
	/**
	 * 根据用户ID查询角色
	 * @param userId
	 * @return
	 */
	List<Role> queryRolesByUserId(Integer userId);
}
8、修改RoleMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itan.mapper.RoleMapper">
  <resultMap id="BaseResultMap" type="com.itan.entity.Role">
    <id column="roleid" jdbcType="INTEGER" property="roleid" />
    <result column="rolename" jdbcType="VARCHAR" property="rolename" />
  </resultMap>
	<!-- 根据用户名查询角色 -->
  <select id="queryRolesByUserId" resultMap="BaseResultMap" >
  	select t1.* from role t1 inner join user_role t2 on(t1.roleid=t2.roleid) where t2.userid=#{value}
  </select>
</mapper>
9、创建Permissionervice
public interface PermissionService {
	/**
	 * 根据用户ID查询权限
	 * @param userId
	 * @return
	 */
	public List<String> queryPermissionByUserId(Integer userId);
}
10、创建PermissionServiceImpl
@Service
public class PermissionServiceImpl implements PermissionService {
	@Autowired
	private PermissionMapper permissionMapper;
	@Override
	public List<String> queryPermissionByUserId(Integer userId) {
		List<Permission> list = permissionMapper.queryPermissionByUserId(userId);
		List<String> perimssions = new ArrayList<>();
		for (Permission permission : list) {
			perimssions.add(permission.getPercode());
		}
		return perimssions;
	}
}
11、修改PermissionMapper
public interface PermissionMapper {
	/**
	 * 根据用户ID查询权限
	 * @param userId
	 * @return
	 */
	List<Permission> queryPermissionByUserId(Integer userId);
}
12、修改PermissionMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itan.mapper.PermissionMapper">
  <resultMap id="BaseResultMap" type="com.itan.entity.Permission">
    <id column="perid" jdbcType="INTEGER" property="perid" />
    <result column="pername" jdbcType="VARCHAR" property="pername" />
    <result column="percode" jdbcType="VARCHAR" property="percode" />
  </resultMap>
  <!-- 根据用户ID查询权限 -->
  <select id="queryPermissionByUserId" resultMap="BaseResultMap">
  	select distinct t1.* from permission t1 inner join role_permission 
  	t2 inner join user_role t3
  	on(t1.perid=t2.perid and t2.roleid=t3.roleid) 
  	where t3.userid=#{value}
  </select>
</mapper>
13、修改UserRealm
public class UserRealm extends AuthorizingRealm {
	@Autowired
	private UserService userService;
	@Autowired
	private PermissionService permissionService;
	@Autowired
	private RoleService roleService;
	/**
	 * 认证
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		//获取用户名
		String username=token.getPrincipal().toString();
		//根据用户名查询用户信息
		User user = userService.queryUserByUserName(username);
		if (null!=user) {
			//查询角色
			List<String> roles = roleService.queryUserByUserId(user.getUserid());
			//查询权限
			List<String> permissions = permissionService.queryPermissionByUserId(user.getUserid());
			ActivierUser activierUser = new ActivierUser(user, roles, permissions);
			//创建盐
			ByteSource credentialsSalt=ByteSource.Util.bytes(user.getUsername()+user.getAddress());
			SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(activierUser,user.getUserpwd(),credentialsSalt,this.getName());
			return info;
		}else {
			return null;
		}
	}
	/**
	 * 授权
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		ActivierUser activierUser = (ActivierUser)principals.getPrimaryPrincipal();
		SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
		List<String> roles = activierUser.getRoles();
		List<String> permissions = activierUser.getPermissions();
		if(null!=roles&&roles.size()>0) {
			info.addRoles(roles);
		}
		if(null!=permissions&&permissions.size()>0) {
			info.addStringPermissions(permissions);
		}
		return info;
	}
}
14、创建index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<jsp:forward page="login/toLogin.action"></jsp:forward>
</body>
</html>
15、创建WEB-INF/view/login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2 align="center">用户登录</h2>
	<form action="${pageContext.request.contextPath }/login/login.action" method="post">
		<table width="50%" align="center" cellpadding="2" cellspacing="2">
			<tr>
				<td align="right">用户名:</td>
				<td>
					<input type="text" name="username">
				</td>
			</tr>
			<tr>
				<td align="right">密码:</td>
				<td>
					<input type="password" name="pwd">
				</td>
			</tr>
			<tr>
				<td align="center" colspan="2">
					<input type="submit" value="登录">
				</td>
			</tr>
		</table>
	</form>
</body>
</html>
16、创建LoginController
@Controller
@RequestMapping("login")
public class LoginController {
	/**
	 * 跳转到登录页面
	 * @return
	 */
	@RequestMapping("toLogin")
	public String toLogin() {
		return "login";
	}
	/**
	 * 登录
	 * @param username
	 * @param pwd
	 * @param session
	 * @return
	 */
	@RequestMapping("login")
	public String login(String username,String pwd,HttpSession session) {
		//得到主体
		Subject subject=SecurityUtils.getSubject();
		UsernamePasswordToken token=new UsernamePasswordToken(username,pwd);
		//锟斤拷录
		try {
			subject.login(token);
			System.out.println("登录成功");
			ActivierUser activierUser=(ActivierUser)subject.getPrincipal();
			session.setAttribute("user", activierUser.getUser());
			return "redirect:/user/toUserManager.action";
		} catch (AuthenticationException e) {
			e.printStackTrace();
			return "redirect:/index.jsp";
		}
	}
}
17、创建UserController
@Controller
@RequestMapping("user")
public class UserController {
	/**
	 * 跳转到用户管理界面
	 * @return
	 */
	@RequestMapping("toUserManager")
	public String toUserManager() {
		return "list";
	}
}
18、创建WEB-INF/view/list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<shiro:hasPermission name="user:query">
	<h1><a href="user/query.action">查询用户</a></h1>
	</shiro:hasPermission>
	<shiro:hasPermission name="user:add">
	<h1><a href="user/add.action">添加用户</a></h1>
	</shiro:hasPermission>
	<shiro:hasPermission name="user:update">
	<h1><a href="user/update.action">修改用户</a></h1>
	</shiro:hasPermission>
	<shiro:hasPermission name="user:delete">
	<h1><a href="user/delete.action">删除用户</a></h1>
	</shiro:hasPermission>
	<shiro:hasPermission name="user:export">
	<h1><a href="user/export.action">导出用户</a></h1>
	</shiro:hasPermission>
</body>
</html>
19、测试

九、springboot整合shiro

1、创建一个springboot项目
  • 勾选Developer Tools所有、web、jdbc、mybatis、mysql Driver
2、加入依赖
<!-- 引入shiro的包 -->
<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-spring</artifactId>
  <version>1.4.1</version>
</dependency>
<!-- thymeleaf依赖 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--shrio和thymeleaf集成的扩展依赖,为了能在页面上使用xsln:shrio的标签 -->
<dependency>
  <groupId>com.github.theborakompanioni</groupId>
  <artifactId>thymeleaf-extras-shiro</artifactId>
  <version>2.0.0</version>
</dependency>
<!--druid数据源依赖-->
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid-spring-boot-starter</artifactId>
  <version>1.1.21</version>
</dependency>
<!--分页插件依赖-->
<dependency>
  <groupId>com.github.pagehelper</groupId>
  <artifactId>pagehelper-spring-boot-starter</artifactId>
  <version>1.2.13</version>
</dependency>
3、配置yml文件
#数据源配置
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/shiro?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC
    username: root
    password: 123456
    druid:
      max-active: 10
      min-idle: 5
      max-wait: 5000
      initial-size: 5
      validation-query: select 1
      stat-view-servlet:
        enabled: true
        login-username: admin
        login-password: admin
        allow:
        deny:
        url-pattern: "/druid/*"
    hikari:
      read-only:
  thymeleaf:
    cache: false
#mybatis的配置
mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations:
  - classpath:mapper/*Mapper.xml
#shiro的配置
shiro:
  #密码加密方式
  hash-algorithm-name: md5
  #散列次数
  hash-iterations: 2
  login-url: /index.html
  #没有认证能访问的资源路径
  anon-urls:
  - /index.html*
  - /login.html*
  - /login/toLogin*
  - /login/login*
  #退出后的路径
  log-out-url: /login/logout*
  #拦截路径
  authc-ulrs:
  - /**
4、entity类
public class Role {
    private Integer roleid;
    private String rolename;
}
public class User {
    private Integer userid;
    private String username;
    private String userpwd;
    private String sex;
    private String address;
}
public class Permission {
    private Integer perid;
    private String pername;
    private String percode;
}
//辅助类在common包下
public class ActivierUser {
	private User user;
	private List<String> roles;
	private List<String> permissions;
	public ActivierUser(User user, List<String> roles, List<String> permissions) {
		super();
		this.user = user;
		this.roles = roles;
		this.permissions = permissions;
	}
}
4、mapper类
public interface UserMapper {
	/**
	 * 根据用户名查询用户对象
	 * @param username
	 * @return
	 */
   User queryUserByUserName(@Param("username") String username);
}
public interface RoleMapper {
	/**
	 * 根据用户ID查询角色
	 * @param userId
	 * @return
	 */
	List<Role> queryRolesByUserId(Integer userId);
}
public interface PermissionMapper {
	/**
	 * 根据用户ID查询权限
	 * @param userId
	 * @return
	 */
	List<Permission> queryPermissionByUserId(Integer userId);
}
5、mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itan.mapper.UserMapper">
	<!-- 根据用户名查询用户 -->
	<select id="queryUserByUserName" resultType="com.itan.entity.User" parameterType="string">
		select * from user where username=#{username}
	</select>
</mapper>
<!--------------------------------------------------------------------------------------------->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itan.mapper.RoleMapper">
  <resultMap id="BaseResultMap" type="com.itan.entity.Role">
    <id column="roleid" jdbcType="INTEGER" property="roleid" />
    <result column="rolename" jdbcType="VARCHAR" property="rolename" />
  </resultMap>
	<!-- 根据用户名查询角色 -->
  <select id="queryRolesByUserId" resultMap="BaseResultMap" >
  	select t1.* from role t1 inner join user_role t2 on(t1.roleid=t2.roleid) where t2.userid=#{value}
  </select>
</mapper>
<!--------------------------------------------------------------------------------------------->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itan.mapper.PermissionMapper">
  <resultMap id="BaseResultMap" type="com.itan.entity.Permission">
    <id column="perid" jdbcType="INTEGER" property="perid" />
    <result column="pername" jdbcType="VARCHAR" property="pername" />
    <result column="percode" jdbcType="VARCHAR" property="percode" />
  </resultMap>
  <!-- 根据用户ID查询权限 -->
  <select id="queryPermissionByUserId" resultMap="BaseResultMap">
  	select distinct t1.* from permission t1 inner join role_permission 
  	t2 inner join user_role t3
  	on(t1.perid=t2.perid and t2.roleid=t3.roleid) 
  	where t3.userid=#{value}
  </select>
</mapper>
6、service类
public interface UserService {
	/**
	 * 根据用户名查询用户对象
	 * @param username
	 * @return
	 */
	public User queryUserByUserName(String username);
}
public interface RoleService {
	/**
	 * 根据用户ID查询角色
	 * @param userId
	 * @return
	 */
	public List<String> queryUserByUserId(Integer userId);
}
public interface PermissionService {
	/**
	 * 根据用户ID查询权限
	 * @param userId
	 * @return
	 */
	public List<String> queryPermissionByUserId(Integer userId);
}
7、impl类
@Service
public class UserServiceImpl implements UserService {
	@Autowired
	private UserMapper userMapper;
	@Override
	public User queryUserByUserName(String username) {
		return userMapper.queryUserByUserName(username);
	}
}
@Service
public class RoleServiceImpl implements RoleService {
	@Autowired
	private RoleMapper roleMapper;
	@Override
	public List<String> queryUserByUserId(Integer userId) {
		List<Role> list = roleMapper.queryRolesByUserId(userId);
		List<String> roles=new ArrayList<String>();
		for (Role role : list) {
			roles.add(role.getRolename());
		}
		return roles;
	}
}
@Service
public class PermissionServiceImpl implements PermissionService {
	@Autowired
	private PermissionMapper permissionMapper;
	@Override
	public List<String> queryPermissionByUserId(Integer userId) {
		List<Permission> list = permissionMapper.queryPermissionByUserId(userId);
		List<String> perimssions = new ArrayList<>();
		for (Permission permission : list) {
			perimssions.add(permission.getPercode());
		}
		return perimssions;
	}
}
8、在realm下新建一个UserRealm类
import java.util.List;
import com.itan.common.ActivierUser;
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.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import com.itan.entity.User;
import com.itan.service.PermissionService;
import com.itan.service.RoleService;
import com.itan.service.UserService;

public class UserRealm extends AuthorizingRealm {
	@Autowired
	private UserService userService;
	@Autowired
	private PermissionService permissionService;
	@Autowired
	private RoleService roleService;
	/**
	 * 认证
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		//获取用户名
		String username=token.getPrincipal().toString();
		//根据用户名查询用户信息
		User user = userService.queryUserByUserName(username);
		if (null!=user) {
			//查询角色
			List<String> roles = roleService.queryUserByUserId(user.getUserid());
			//查询权限
			List<String> permissions = permissionService.queryPermissionByUserId(user.getUserid());
			ActivierUser activierUser = new ActivierUser(user, roles, permissions);
			//创建盐
			ByteSource credentialsSalt=ByteSource.Util.bytes(user.getUsername()+user.getAddress());
			SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(activierUser,user.getUserpwd(),credentialsSalt,this.getName());
			return info;
		}else {
			return null;
		}
	}
	/**
	 * 授权
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		ActivierUser activierUser = (ActivierUser)principals.getPrimaryPrincipal();
		SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
		List<String> roles = activierUser.getRoles();
		List<String> permissions = activierUser.getPermissions();
		if(null!=roles&&roles.size()>0) {
			info.addRoles(roles);
		}
		if(null!=permissions&&permissions.size()>0) {
			info.addStringPermissions(permissions);
		}
		return info;
	}
}
9、在config下新建ShiroAutoConfiguration类
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.itan.realm.UserRealm;
import lombok.Data;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;
import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;

@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(value = { SecurityManager.class })
@ConfigurationProperties(prefix = "shiro")
@Data
public class ShiroAutoConfiguration {
    private static final String SHIRO_DIALECT = "shiroDialect";
    private static final String SHIRO_FILTER = "shiroFilter";
    private String hashAlgorithmName = "md5";// 加密方式
    private int hashIterations = 2;// 散列次数
    private String loginUrl = "/index.html";// 默认的登陆页面
    private String logOutUrl;
    private String[] anonUrls;
    private String[] authcUlrs;

    /**
     * 声明凭证匹配器
     */
    @Bean
    public HashedCredentialsMatcher credentialsMatcher(){
        HashedCredentialsMatcher credentialsMatcher=new HashedCredentialsMatcher();
        //加密方式
        credentialsMatcher.setHashAlgorithmName(hashAlgorithmName);
        //散列次数
        credentialsMatcher.setHashIterations(hashIterations);
        return credentialsMatcher;
    }

    /**
     * 创建userRealm
     * @param credentialsMatcher:凭证匹配器
     * @return
     */
    @Bean
    public UserRealm userRealm(CredentialsMatcher credentialsMatcher){
        UserRealm userRealm=new UserRealm();
        //注入凭证匹配器
        userRealm.setCredentialsMatcher(credentialsMatcher);
        return userRealm;
    }

    /**
     * 声明安全管理器
     * @param userRealm
     * @return
     */
    @Bean("securityManager")
    public SecurityManager securityManager(UserRealm userRealm){
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
        //注入UserRealm
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    /**
     * 配置shiro的过滤器
     */
    @Bean(SHIRO_FILTER)
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        // 设置安全管理器
        factoryBean.setSecurityManager(securityManager);
        // 设置未登陆的时要跳转的页面
        factoryBean.setLoginUrl(loginUrl);
        Map<String, String> filterChainDefinitionMap = new HashMap<>();
        // 设置放行的路径
        if (anonUrls != null && anonUrls.length > 0) {
            for (String anon : anonUrls) {
                filterChainDefinitionMap.put(anon, "anon");
            }
        }
        // 设置退出的路径
        if (null != logOutUrl) {
            filterChainDefinitionMap.put(logOutUrl, "logout");
        }
        // 设置拦截的路径
        if (authcUlrs != null && authcUlrs.length > 0) {
            for (String authc : authcUlrs) {
                filterChainDefinitionMap.put(authc, "authc");
            }
        }
        Map<String, Filter> filters=new HashMap<>();
        //配置过滤器
        factoryBean.setFilters(filters);
        factoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return factoryBean;
    }

    /**
     * 注册shiro的委托过滤器,相当于之前在web.xml里面配置的
     * @return
     */
    @Bean
    public FilterRegistrationBean<DelegatingFilterProxy> delegatingFilterProxy(){
        //创建注册器
        FilterRegistrationBean<DelegatingFilterProxy> bean = new FilterRegistrationBean<>();
        //创建过滤器
        DelegatingFilterProxy proxy=new DelegatingFilterProxy();
        proxy.setTargetFilterLifecycle(true);
        proxy.setTargetBeanName(SHIRO_FILTER);
        bean.setFilter(proxy);
        return bean;
    }
    /* 加入注解的使用,不加入这个注解不生效--开始 */
    /**
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }
    /* 加入注解的使用,不加入这个注解不生效--结束 */
    /**
     * 这里是为了能在html页面引用shiro标签,上面两个函数必须添加,不然会报错
     * @return
     */
    @Bean(name = SHIRO_DIALECT)
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }
}
10、controller类
@Controller
@RequestMapping("login")
public class LoginController {
	/**
	 * 登录
	 * @param username
	 * @param pwd
	 * @param session
	 * @return
	 */
	@RequestMapping("login")
	public String login(String username,String pwd,HttpSession session) {
		//得到主体
		Subject subject=SecurityUtils.getSubject();
		UsernamePasswordToken token=new UsernamePasswordToken(username,pwd);
		//锟斤拷录
		try {
			subject.login(token);
			System.out.println("登录成功");
			ActivierUser activierUser=(ActivierUser)subject.getPrincipal();
			session.setAttribute("user", activierUser.getUser());
			return "redirect:/user/toUserManager";
		} catch (AuthenticationException e) {
			e.printStackTrace();
			return "redirect:/index.html";
		}
	}
}
//用户控制器
@Controller
@RequestMapping("user")
public class UserController {
	/**
	 * 跳转到用户管理界面
	 * @return
	 */
	@RequestMapping("toUserManager")
	public String toUserManager() {
		return "list";
	}
}
11、启动类
  • 在启动类上加注解扫描mapper包下的类
  • @MapperScan(basePackages = {“com.itan.mapper”})
12、在static下新建一个index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<h2 align="center">用户登录</h2>
<form action="/login/login" method="post">
    <table width="50%" align="center" cellpadding="2" cellspacing="2">
        <tr>
            <td align="right">用户名:</td>
            <td><input type="text" name="username"></td>
        </tr>
        <tr>
            <td align="right">密码:</td>
            <td><input type="password" name="pwd"></td>
        </tr>
        <tr>
            <td align="center" colspan="2">
                <input type="submit" value="登录">
            </td>
        </tr>
    </table>
</form>
</body>
</html>
13、在templates下新建list.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <meta charset="UTF-8">
    <title>列表</title>
</head>
<body>
    <h1 shiro:hasPermission="user:query "><a href="">查询用户</a></h1>
    <h1 shiro:hasPermission="user:add"><a href="">添加用户</a></h1>
    <h1 shiro:hasPermission="user:update"><a href="">修改用户</a></h1>
    <h1 shiro:hasPermission="user:delete"><a href="">删除用户</a></h1>
    <h1 shiro:hasPermission="user:export"><a href="">导出用户</a></h1>
</body>
</html>
14、启动测试,根据不同的用户list页面显示出不同的权限
;