小白学习应用spring-shiro

本文档详细介绍了如何使用Spring Boot、Maven、Thymeleaf和Shiro进行Web应用的基础环境搭建、Thymeleaf模板引擎的引入与测试、Shiro的认证与授权流程,以及Shiro与Mybatis的整合,最终实现动态资源权限拦截。通过创建Shiro的配置类、 Realm以及过滤器,结合Thymeleaf的权限标签,展示了完整的Shiro权限管理基础应用。
摘要由CSDN通过智能技术生成

spring shiro基础学习(感谢各位大大能够给小编一个赞,有好的建议下方评论区留言哟,大家一起努力!)

b站学习地址

环境与软件准备:
1.jdk1.8
2.eclpse开发工具(2018)
3.mybatis
4.navicate
5.win10

1.maven快速搭建并测试

1.1下载并简单配置maven

注意:配置maven的一些注意事项
1.maven下载地址:http://maven.apache.org/download.cgi

点击下载
2.下载后解压到可以长期使用的环境下,以便日后简单调用。(我解压到了D盘)
解压后的常规操作:

(1). 对D:\apache-maven-3.6.3\conf下的settings.xml的本地仓库位置进行配置(从别当仓库下载下来的依赖会下载到本地仓库)
在这里插入图片描述
(2). 对于settings.xml镜像的修改(强烈建议修改)
在这里插入图片描述

1.2eclipse运用maven快速搭建环境

1.Window->preference->Maven->Installations点击add后如下添加

在这里插入图片描述
2.选择配置好的maven并apply

在这里插入图片描述

3.在eclipse中添加maven project如下图点击next
在这里插入图片描述
4.再填写如下,点击finish,就建立了一个maven的项目
在这里插入图片描述
5.配置pom.xml。

<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>
  
  <!-- springboot父工程 -->
  <parent>
  		<groupId>org.springframework.boot</groupId>
  		<artifactId>spring-boot-starter-parent</artifactId>
  		<version>1.5.4.RELEASE</version>
  </parent>
  
  <groupId>cn.itheima.com</groupId>
  <artifactId>spring-shiro</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <dependencies>
  		<!-- web启动器 -->
  		<dependency>
  			<groupId>org.springframework.boot</groupId>
  			<artifactId>spring-boot-starter-web</artifactId>
  		</dependency>
  		<!-- 引入thymeleaf -->
  		<dependency>
  			<groupId>org.springframework.boot</groupId>
  			<artifactId>spring-boot-starter-thymeleaf</artifactId>
  		</dependency>
  		<!-- 引入shiro -->
  		<dependency>
  			<groupId>org.apache.shiro</groupId>
  			<artifactId>shiro-spring</artifactId>
  			<version>1.4.0</version>
  		</dependency>
  		
  		
  		<!-- 导入mybatis -->
  		<dependency>
  			<groupId>com.alibaba</groupId>
  			<artifactId>druid</artifactId>
  			<version>1.0.9</version>
  		</dependency>
  		<!-- 导入mysql -->
  		<dependency>
  			<groupId>mysql</groupId>
  			<artifactId>mysql-connector-java</artifactId>
  		</dependency>
  		<!-- 导入SpringBoot的mybatis启动器 -->
  		<dependency>
  			<groupId>org.mybatis.spring.boot</groupId>
  			<artifactId>mybatis-spring-boot-starter</artifactId>
  			<version>1.1.1</version>
  		</dependency>
  		
  		<!-- thymeleaf对shiro扩展坐标 -->
  		<dependency>
  			<groupId>com.github.theborakompanioni</groupId>
  			<artifactId>thymeleaf-extras-shiro</artifactId>
  			<version>2.0.0</version>
  		</dependency>
  </dependencies>
  
  <!-- 修改jdk版本和thymeleaf的版本 -->
  <properties>
  		<java.version>1.8</java.version>
  		<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
  		<thymeleaf-layout-dialect.version>2.0.4</thymeleaf-layout-dialect.version>
  </properties>
</project>

这样子springboot环境和一些其它主要环境就搭建好了

1.3测试环境

在main里面创建controller类和启动类
在这里插入图片描述
一般springboot启动是用Application来启动代码如下

UserController

package cn.itheima.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class UserController {
	@RequestMapping("/hello")
	@ResponseBody
	public String hello() {
		System.out.println("测试成功");
		return "hello";
	}
}

Application

package cn.itheima;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

//启动类
@SpringBootApplication
public class Application {
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

运行后访问成功:
在这里插入图片描述

2.thymeleaf模板引入并测试

对应xml:

<!-- 引入thymeleaf -->
  		<dependency>
  			<groupId>org.springframework.boot</groupId>
  			<artifactId>spring-boot-starter-thymeleaf</artifactId>
  		</dependency>

2.1 布置测试

在src/main/resource下创建templates文件夹
在这里插入图片描述
在UserController中写入测试代码

//测试thymeleaf
	@RequestMapping("/testThymeleaf")
	public String testThymeleaf(Model model) {
		//把数据放入model
		model.addAttribute("name","黑马程序员");
		
		//返回test.html
		return "test";
	}

在templates下创建test.html,利用thymeleaf语法获取controller数据

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3 th:text="${name}"></h3>
</body>
</html>

运行后:
在这里插入图片描述

注意:因为Thymeleaf版本问题在建立html页面的时候如果是3,0以下的需要在<meta charset="UTF-8">中加结束语,不过建议进行升级在pom.xml文件下按如下修改

<properties>
  		<java.version>1.8</java.version>
  		<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
  		<thymeleaf-layout-dialect.version>2.0.4</thymeleaf-layout-dialect.version>
</properties>

修改后运行:
在这里插入图片描述

3.shiro认证

名称对应意思
Subject用户主体
SecurityManager安全管理器
Realmshiro连接数据库的桥梁

导入shiro依赖:

<!-- 引入shiro -->
  		<dependency>
  			<groupId>org.apache.shiro</groupId>
  			<artifactId>shiro-spring</artifactId>
  			<version>1.4.0</version>
  		</dependency>

3.1创建shiro的配置类

创建ShiroConfig类和UserRealm类
ShiroConfig

package cn.itheima.shiro;

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


//shiro的配置类
@Configuration
public class ShiroConfig {
	//创建shiroFilterFactoryBean
	@Bean
	public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		
		//设置安全管理器
		shiroFilterFactoryBean.setSecurityManager(securityManager);

		
		return shiroFilterFactoryBean;
	}
	
	//创建DefaultWebSecurityManager
	@Bean(name="securityManager")
	public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm) {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		//关联realm
		securityManager.setRealm(userRealm);
		return securityManager;
	}
	
	//创建Realm
	@Bean(name="userRealm")
	public UserRealm getRealm() {
		return new UserRealm();
	}
}

UserRealm

package cn.itheima.shiro;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

public class UserRealm extends AuthorizingRealm{

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		// TODO Auto-generated method stub
		System.out.println("执行授权逻辑");
		return null;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		// TODO Auto-generated method stub
		System.out.println("执行认证逻辑");
		return null;
	}

}

3.2 执行shiro认证-使用shiro过滤器实现认证资源拦截

templates下添加user文件夹,添加add.html和update.html
add.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>用户添加页面</title>
</head>
<body>
用户添加
</body>
</html>

update.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>用户更新</title>
</head>
<body>
用户更新
</body>
</html>

对test.html进行form修改和controller更改

注意:所有页面的跳转都要经过controller进行跳转不能单纯的静态跳转

test.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3 th:text="${name}"></h3>
用户添加:<a href="add">用户添加</a><br/>
用户更新:<a href="update">用户更新</a><br/>
</body>
</html>

UserController.java

@RequestMapping("/add")
	public String add() {
		return "/user/add";
		
	}
	
	@RequestMapping("/update")
	public String update() {
		return "/user/update";
		
	}

测试后能正常访问
add.html

过滤

Shiro内置过滤器,可以实现权限相关的拦截器
* 常用的过滤器:
* anon: 无需认证可以访问
* authc: 必须认证才可以访问
* user:如果使用rememberMe的功能可以直接访问
* perms:必须授予资源权限
* role:角色授权

注意:@Configuration在ShiroConfig类的注解不可或缺否则怎么写拦截器也没用,所有类里面的方法都必须要有**@Bean**注解才能够被spring识别到。

ShiroConfig.java

//创建shiroFilterFactoryBean
	@Bean
	public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		
		//设置安全管理器
		shiroFilterFactoryBean.setSecurityManager(securityManager);

		Map<String,String> filterMap  = new LinkedHashMap<String,String>();
		//拦截add页面请求
		filterMap.put("/add","authc");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
		
		return shiroFilterFactoryBean;
	}

运行后:
在这里插入图片描述

修改跳转页面完成登录的拦截

ShiroConfig.java

//创建shiroFilterFactoryBean
	@Bean
	public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		
		//设置安全管理器
		shiroFilterFactoryBean.setSecurityManager(securityManager);

		Map<String,String> filterMap  = new LinkedHashMap<String,String>();
		
		//设置放行页面
		filterMap.put("/testThymeleaf", "anon");
		
		//拦截所有页面请求
		filterMap.put("/*","authc");
		
		//修改调整的登录页面
		shiroFilterFactoryBean.setLoginUrl("/toLogin");
		
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
		
		return shiroFilterFactoryBean;
	}

在编写html的时候要求,form表单的<form method="post" action="login">post方法可以使得密码账户不显示,action="login"可以使得执行login的动作,千万记住要加漏加使得usercontroller里的login方法不执行。

login.html创建在templates目录下

login.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<h3>登录</h3>
<font color="red" th:text="${msg}"></font>
<form method="post" action="login">
	用户名:<input type="text" name="name"/><br/>
	密码:<input type="password" name="password"/><br/>
	<input type="submit" value="登录"/>
</body>
</html>

运行testThymeleaf,没有被拦截
在这里插入图片描述
点击下面的链接,成功拦截至toLogin
在这里插入图片描述

3.3 实现登录

首先在UserController中添加登录逻辑

//	登录逻辑处理
	@RequestMapping("/login")
	public String login(String name,String password,Model model) {
		/*
		 * 使用shiro编写认证操作
		 */
		//1.获取Subject
		Subject subject = SecurityUtils.getSubject();
		
		//2.封装用户数据
		UsernamePasswordToken token = new UsernamePasswordToken(name,password);
		
		//3.执行登录方法
		try {
			subject.login(token);
			
			//登陆成功
			return "redirect:/testThymeleaf";
		} catch (UnknownAccountException e) {
			
			model.addAttribute("msg","用户名不存在");
			return "login";
		}catch (IncorrectCredentialsException e) {
			
			model.addAttribute("msg","密码错误");
			return "login";
		}
		
	}

由于前面的页面功能全部拦截导致无法实现login请求所以给login添加放行,对ShiroConfig编写
添加filterMap.put("/login", "anon");即可

再对UserRealm进行修改,判断用户名和密码

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
		
		System.out.println("执行认证逻辑");
		
		//编写shiro判断逻辑,判断用户名和密码
		String name = "root";
		String password = "123";
		//1.判断用户名
		UsernamePasswordToken token = (UsernamePasswordToken)arg0;
		
		if(!token.getUsername().equals(name)) {
			//用户名不存在
			return null;//shiro底层会抛出UnKnowAccountException
		}
		
		//2.判断密码
				
		return new SimpleAuthenticationInfo("",password,"");
	
	}

a.用户名不存在
在这里插入图片描述
b.密码错误
在这里插入图片描述

3.4 连接mybatis实现登录

导入mybatis相关依赖

		<!-- 导入mybatis -->
  		<dependency>
  			<groupId>com.alibaba</groupId>
  			<artifactId>druid</artifactId>
  			<version>1.0.9</version>
  		</dependency>
  		<!-- 导入mysql -->
  		<dependency>
  			<groupId>mysql</groupId>
  			<artifactId>mysql-connector-java</artifactId>
  		</dependency>
  		<!-- 导入SpringBoot的mybatis启动器 -->
  		<dependency>
  			<groupId>org.mybatis.spring.boot</groupId>
  			<artifactId>mybatis-spring-boot-starter</artifactId>
  			<version>1.1.1</version>
  		</dependency>

固定写法在resource下面写Application.properties
Application.properties

spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot-shiro
spring.datasource.username=root
spring.datasource.password=root

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

mybatis.type-aliases-package=cn.itheima.domain

创建相应的数据库信息,以下是我的创建
在这里插入图片描述

创建用户实体
User.java

package cn.itheima.domain;

public class User {
	private Integer id;
	private String name;
	private String password;
	
	private String perms;
	public String getPerms() {
		return perms;
	}
	public void setPerms(String perms) {
		this.perms = perms;
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}

}

创建cn.itheima.mapper包再创建UserMapper接口
UserMapper.java

package cn.itheima.mapper;

import cn.itheima.domain.User;

public interface UserMapper {

	public User findByName(String name);
}

在创建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">
<!-- 该文件存放CRUD的sql语句 -->
<mapper namespace="cn.itheima.mapper.UserMapper">
	
	<select id="findByName" parameterType="string" resultType="user">
		SELECT id,
		name,
		password,
		perms
		FROM
		user where name = #{value}
	</select>
	
</mapper>

创建service对功能实现(service接口和接口实现)
在cn.itheima.service下面创建接口,并且在cn.itheima.service.impl下面实现接口
UserService

package cn.itheima.service;

import cn.itheima.domain.User;

public interface UserService {
	public User findByName(String name);

}

UserServiceImpl

package cn.itheima.service.impl;

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

import cn.itheima.domain.User;
import cn.itheima.mapper.UserMapper;
import cn.itheima.service.UserService;

@Service
public class UserServiceImpl implements UserService{
	
	//创建userMapper对象
	@Autowired
	private UserMapper userMapper;
	
	@Override
	public User findByName(String name) {
		return userMapper.findByName(name);
	}

}

如果发现@Override加了后findByName有错那么可能是因为没有成功修改jdk的版本,updat以下maven project

在UserRealm进行修改

//注入userservice
	@Autowired
	private UserService userService;
	
	
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
		
		System.out.println("执行认证逻辑");
		
		//1.判断用户名
		UsernamePasswordToken token = (UsernamePasswordToken)arg0;
		
		User user = userService.findByName(token.getUsername());
		
		if(user == null) {
			//用户名不存在
			return null;//shiro底层会抛出UnKnowAccountException
		}
		
		//2.判断密码
				
		return new SimpleAuthenticationInfo("",user.getPassword(),"");
	
	}

可以实现与数据库的连接。

3.5 资源连接数据库动态拦截

在ShiroConfig中添加拦截和页面跳转

		//授权过滤器(被拦截后跳转未授权页面)
		filterMap.put("/add", "perms[user:add]");
		filterMap.put("/update", "perms[user:update]");
		//修改未授权页面
		shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");

拦截的时候遇到个错误就是无法拦截不是代码错误是代码书写顺序的错误
//授权过滤器(被拦截后跳转未授权页面) filterMap.put("/add", "perms[user:add]"); filterMap.put("/update", "perms[user:update]");
要写在filterMap.put("/*","authc");这个之前不然无法拦截,详细原因正在了解中。

创建noAuth.html
noAuth.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>未经授权访问</title>
</head>
<body>
亲未经授权访问该页面
</body>
</html>

在controller中添加对应跳转

@RequestMapping("/noAuth")
	public String noAuth() {
		return "/noAuth";
		
	}

在mapper接口中创建findById

public User findById(Integer id);

在mapper的xml中实现sql

<select id="findById" parameterType="int" resultType="user">
		SELECT id,
		name,
		password,
		perms
		FROM
		user where id = #{value}
	</select>

实现业务(接口创建和实现)
UserService

public User findById(Integer id);

UserServiceImpl

@Override
	public User findById(Integer id) {
		
		return userMapper.findById(id);
	}

在UserRealm中编辑授权逻辑

其中user的获取是通过getPrincipal方法获取,principal通过认证逻辑下SimpleAuthenticationInfo的第一个参数获取到user对象,千万不要忘记在认证逻辑下添加第一个参数user.

//给资源授权
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		
		//获取当前登录用户
		Subject subject = SecurityUtils.getSubject();
		User user = (User)subject.getPrincipal();
		
		User dbUser = userService.findById(user.getId());
		
		info.addStringPermission(dbUser.getPerms());
		
		return info;

此时授权基本已完成。

4.thymeleaf与shiro整合

导入扩展依赖

<!-- thymeleaf对shiro扩展坐标 -->
  		<dependency>
  			<groupId>com.github.theborakompanioni</groupId>
  			<artifactId>thymeleaf-extras-shiro</artifactId>
  			<version>2.0.0</version>
  		</dependency>

在shiroconfig中编写

//配置ShiroDialect,用于thymeleaf和shiro标签配合使用
	@Bean
	public ShiroDialect getShiroDialect() {
		return new ShiroDialect();
	}

在test.html中编写相关限制

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>test thymeleaf</title>
</head>
<body>

<h3 th:text="${name}"></h3>

<hr>
<div shiro:hasPermission="user:add">
用户添加:<a href="add">用户添加</a><br/>
</div>
<div shiro:hasPermission="user:update">
用户更新:<a href="update">用户更新</a><br/>
</div>
<a href="toLogin">登录</a>
</body>
</html>

到这里就全部编写完成了。

学习心得

跟着这个视频学习能够掌握shiro的应用和实现,建议看视频的时候把弹幕关掉,里面有很多值得学习的很适合耐心的初学者,虽然里面老师有一些错误但是错误也是这的学习的,避免以后的错误的发生。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值