spring shiro基础学习(感谢各位大大能够给小编一个赞,有好的建议下方评论区留言哟,大家一起努力!)
环境与软件准备:
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 | 安全管理器 |
Realm | shiro连接数据库的桥梁 |
导入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";
}
测试后能正常访问
过滤
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的应用和实现,建议看视频的时候把弹幕关掉,里面有很多值得学习的很适合耐心的初学者,虽然里面老师有一些错误但是错误也是这的学习的,避免以后的错误的发生。