SpringBoot之Shiro整合登陆验证、角色验证和权限验证

首先要感谢这篇文章的博主,参考文章http://www.ityouknow.com/springboot/2017/06/26/springboot-shiro.html

以下就要开始我的表演啦(我还是一个菜鸟,大佬请绕道)

这一次我是用SpringBoot搭建,推荐大家学习Shiro的时候,从开始的shiro.ini配置文件开始学习起,废话不多说,先看数据表结构。

SpringBoot之Shiro整合登陆验证、角色验证和权限验证

再看看我的pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.xiaobin</groupId>
	<artifactId>SpringbootShiro</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<name>SpringbootShiro</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.9.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>net.sourceforge.nekohtml</groupId>
			<artifactId>nekohtml</artifactId>
			<version>1.9.22</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.4.0</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
		<dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>

这里的模版是用的thymeleaf,需要在src/main/resources/templates创建六个页面,如下图:

SpringBoot之Shiro整合登陆验证、角色验证和权限验证

页面内容很简单,都是一些文字提示,没有具体的操作内容,除了login.html有一个form提交表单。

再来看看我的application.yml配置文件

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/shiro?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 
  thymeleaf: 
       cache: false
       mode: LEGACYHTML5
mybatis:
  mapper-locations: classpath:mapper/*.xml

在然后就是dao层和service层的东西就贴个图吧(嘻嘻,偷懒)

SpringBoot之Shiro整合登陆验证、角色验证和权限验证

配置shiro的重中之重来啦,打起精神。

首先需要自己配置一个集成org.apache.shiro.realm.AuthorizingRealm类,主要是来验证登陆和权限

public class MyShiroRealm extends AuthorizingRealm {

	@Autowired
	private UserDaoService userDaoService;
	@Autowired
	private RoleDaoService roleDaoService;
	@Autowired
	private PermissionDaoService permissionDaoService;
	
	
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		// 能进入到这里,表示账号已经通过验证了
		String username = (String) principals.getPrimaryPrincipal();
		User user = userDaoService.selectByNameUser(username);
		//先把所拥有的角色给获取
		Set<String> roleString = roleDaoService.selectByUserIdString(user.getUserId());
		//查询该用户所拥有的角色
		List<Role> roleList = roleDaoService.selectByUserIdRoles(user.getUserId());
		//查询所有角色所拥有的权限
		Set<String> perms = new HashSet<>();
		for(Role role : roleList) {
			Set<String> permString = permissionDaoService.selectByRoleIdPermissionString(role.getRoleId());
			perms.addAll(permString);
		}
		
		// 授权对象
		SimpleAuthorizationInfo s = new SimpleAuthorizationInfo();
		// 把通过DAO获取到的角色和权限放进去
		s.setStringPermissions(perms);
		s.setRoles(roleString);
		return s;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		// TODO Auto-generated method stub
		//获取登陆的用户名和密码
		UsernamePasswordToken t = (UsernamePasswordToken) token;
		String username = token.getPrincipal().toString();
		String password = new String(t.getPassword());
		//从数据库中获取登陆的用户
		User user = userDaoService.selectByNameUser(username);
		if(null==user) {
			System.out.println("没找到此用户");
			throw new AuthenticationException();
		}
		//把用户输入的密码进行md5和盐加密一起运算两次
		String encodedPassword = new SimpleHash("md5", password, user.getSalt(), 2).toString();
		if (!user.getPassword().equals(encodedPassword)) {
			System.out.println("密码错误");
			throw new AuthenticationException();
		}
		// 认证信息里存放账号密码, getName() 是当前Realm的继承方法,通常返回当前类名 :databaseRealm
		SimpleAuthenticationInfo a = new SimpleAuthenticationInfo(username, password, getName());
		return a;
	}

}

然后再试shiro的全局配置啦,Apache Shiro 核心通过 Filter 来实现

@Configuration
public class ShiroConfig {
	@Bean
	public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		// 拦截器
		Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
		// 配置不会被拦截的链接 顺序判断
		filterChainDefinitionMap.put("/static/**", "anon");
		filterChainDefinitionMap.put("/index", "anon");
		// 配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
		filterChainDefinitionMap.put("/logout", "logout");
		// <!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
		// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
		//这里可以手动加入角色和权限
		// filterChainDefinitionMap.put("/userinfo","roles[admin],perms[userList]");
		// filterChainDefinitionMap.put("/userAdd","roles[userManger]");
		filterChainDefinitionMap.put("/**", "authc");
		// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
		shiroFilterFactoryBean.setLoginUrl("/login");
		// 登录成功后要跳转的链接
		shiroFilterFactoryBean.setSuccessUrl("/index");

		//没有授权就会跳转到403.html  这里我的好像没有效,我用的是MyException来捕捉没有权限的异常
		shiroFilterFactoryBean.setUnauthorizedUrl("/403");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return shiroFilterFactoryBean;
	}

	//自定义Realm拦截处理,这个类很重要
	@Bean
	public MyShiroRealm myShiroRealm() {
		MyShiroRealm myShiroRealm = new MyShiroRealm();
		return myShiroRealm;
	}

	@Bean
	public SecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(myShiroRealm());
		return securityManager;
	}

	/**
	    *  开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
	    * 配置以下两个bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)即可实现此功能
	    * @return
	    */
	   @Bean
	   public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
	       DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
	       advisorAutoProxyCreator.setProxyTargetClass(true);
	       return advisorAutoProxyCreator;
	   }
	 
	   /**
	    * 开启aop注解支持
	    * @param securityManager
	    * @return
	    */
	   @Bean
	   public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
	       AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
	       authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
	       return authorizationAttributeSourceAdvisor;
	   }
}

shiro配置基本就完结啦现在我们添加Controller来测试一下

@Controller
public class IndexController {
	
	@RequestMapping({"/","/index"})
	public String index() {
		return "index";
	}
	
	/**
	 * 页面login.html中form表单action的提交地址
	 * 不处理登陆验证,假如还是跳转到/login.html就是用户或者密码错误
	 * @param map
	 * @return
	 */
	@RequestMapping("login")
	public String login(){
		return "login";
	}
	
	/**
	 * 没有权限就会跳转到403.html
	 * @return
	 */
	@RequestMapping("/403")
	public String unauthorizedRole() {
		return "403";
	}
}

还有一个Controller是对其它三个页面的跳转,主要是使用@RequiresRoles和@RequiresPermissions两个注解

@Controller
public class UserController {

	
	/**
	 * 访问用户列表页面
	 * @return
	 */
	@RequestMapping("/userlist")
	@RequiresPermissions("userList")//我的用户并没有userList这个权限,所以访问不了	
	public String userlist() {
		return "userInfo";
	}
	
	/**
	 * 访问用户增加页面
	 * @return
	 */
	@RequestMapping("/useradd")
	@RequiresRoles("admin")//我的用户并没有admin这个角色,所以访问不了
	public String useradd() {
		return "userAdd";
	}
	/**
	 * 访问用户删除页面
	 * @return
	 */
	@RequestMapping("/userdelete")
	public String userdelete() {
		return "userDelete";
	}
}

结果图

SpringBoot之Shiro整合登陆验证、角色验证和权限验证SpringBoot之Shiro整合登陆验证、角色验证和权限验证SpringBoot之Shiro整合登陆验证、角色验证和权限验证

码云地址:https://gitee.com/MyXiaoXiaoBin/SpringBootShiro

 

每天都有一个小目标,让自己不在那么迷茫