承接上一篇博客:https://blog.csdn.net/qq_41115379/article/details/112978080
这是下一篇博客:https://blog.csdn.net/qq_41115379/article/details/113088489
首先要说的是,这个项目实战是参考自黑马,可以去对应视频看一看:https://www.bilibili.com/video/BV1ct411x7CN
接下来按照这几个步骤
首先要了解,shiro有着几个核心api
subject:用户主体(把操作交给SecurityManager)
SecurityManager:安全管理器(关联Realm)
Realm:shiro连接数据的桥梁
然后是在pox里导入shiro的依赖
<!-- 导入shiro和spring整合依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
并且自定义一个Realm类
package com.example.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;
/**
* 自定义的Realm shiro有两个功能,认证和授权,所以刚好实现这两个功能
*/
public class UserRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行授权逻辑");
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行认证逻辑");
return null;
}
}
然后是创建shiro类
package com.example.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;
@Configuration
public class ShiroConfig {
/**
* 创建Realm bean会让方法返回的对象放入到spring的环境,以便使用
*/
@Bean(name = "userRealm")
public UserRealm getRealm(){
return new UserRealm();
}
/**
* 创建DefaultWebSecurityManager
*/
//这里的传参有点特殊可以调用一个注解,这里有个细节,想看看注解区不区分大小写
//实测,会报错。。。所以是区分大小写的
// @Qualifier 注释指定注入 Bean 的名称,是用来消除歧义的
//这里也要有Bean
@Bean(name = "defaultWebSecurityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
//关联realm,并且这个是需要传参的
defaultWebSecurityManager.setRealm(userRealm);
return defaultWebSecurityManager;
//感觉和直接return一个 new的一样吧 之所以不直接return是因为,会调用一个
//关联realm的方法
}
/**
* 创建shiroFilterFactoryBean
*/
//也是需要注解和参数的
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
//设置一个安全管理器来关联SecurityManager
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
return shiroFilterFactoryBean;
}
}
位置如下
使用shiro内置过滤器实现页面拦截
先在templates下创建用户添加add.html和用户更新的界面update.html
add.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户添加页面</title>
</head>
<body>
用户添加
</body>
</html>
update.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户更新页面</title>
</head>
<body>
用户更新
</body>
</html>
并且修改test.html 让他能跳转到这两个其他的界面
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试用的</title>
</head>
<body>
<hs th:text="${name}"></hs>
<hr/>
进入用户添加功能:<a href="user/add.html">用户添加</a><br/>
进入用户更新功能:<a href="user/update.html">用户更新</a><br/>
</body>
</html>
结构如下:
然后就可以启动application
浏览器输入
http://localhost:8080/testThymeleaf
但是会发现,点击用户添加或者用户更新,都会出现
解决方法的话,主要是在于这个项目是用spring写的,所以都是用的自动装配,所以直接在controller那边新加入这两个就可以了
UserController新添加的类
//用户的增加
@RequestMapping("/add")
public String add(){
System.out.println("UserController.add()");
//这里返回的是路径
//所以是需要删除ResponseBody
return "user/add";
}
//用户的更新
@RequestMapping("/update")
public String update(){
System.out.println("UserController.update()");
//同理返回路径
return "user/update";
}
并把test再修改一下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试用的</title>
</head>
<body>
<hs th:text="${name}"></hs>
<hr/>
进入用户添加功能:<a href="add">用户添加</a><br/>
进入用户更新功能:<a href="update">用户更新</a><br/>
</body>
</html>
再开始正式添加shiro内置过滤器,先介绍一下,他有五种:
anon:无序认证(登录)就可以访问
authc:必须认证才可以访问
user:如果使用rememberMe的功能可以直接访问
perms:该资源必须得到资源权限才可以访问
role:该资源必须得到角色权限才可以访问
然后往shiroConfig里添加数据
package com.example.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;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
/**
* 创建Realm bean会让方法返回的对象放入到spring的环境,以便使用
*/
@Bean(name = "userRealm")
public UserRealm getRealm(){
return new UserRealm();
}
/**
* 创建DefaultWebSecurityManager
*/
//这里的传参有点特殊可以调用一个注解,这里有个细节,想看看注解区不区分大小写
//实测,会报错。。。所以是区分大小写的
// @Qualifier 注释指定注入 Bean 的名称,是用来消除歧义的
//这里也要有Bean
@Bean(name = "defaultWebSecurityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
//关联realm,并且这个是需要传参的
defaultWebSecurityManager.setRealm(userRealm);
return defaultWebSecurityManager;
//感觉和直接return一个 new的一样吧 之所以不直接return是因为,会调用一个
//关联realm的方法
}
/**
* 创建shiroFilterFactoryBean
*/
//也是需要注解和参数的
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
//设置一个安全管理器来关联SecurityManager
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
//添加shiro内置过滤器
//先创建一个Map集合
Map<String,String> filterMap=new LinkedHashMap<String,String>();
//然后往里面添加东西
filterMap.put("/add","authc");
filterMap.put("/update","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
}
然后启动这个application
会发现这个错误:
拦截成功会默认到这个jsp文件 所以需要进行修改,到我们让他跳转的页面
所以有一个新写的login方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
登录页面
</body>
</html>
然后对应的改写UserController和在shiro里面增加对应的功能
UserController
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UserController {
//测试方法
@ResponseBody
@RequestMapping("/hello")
public String hello(){
System.out.println("UserController.hello()");
return "ok";
}
//在使用 @RequestMapping后,返回值通常解析为跳转路径,
// 但是加上 @ResponseBody 后返回结果不会被解析为跳转路径,而是直接写入 HTTP response body
//测试thymeleaf
//所以注意的是 这边是没加@ResponseBody,也就是他就是一个跳转路径,所以要创建一个test
@RequestMapping("/testThymeleaf")
public String testThymeleaf(Model model){
//把数据存入到model中
model.addAttribute("name","wzw");
//返回界面
return "test";
}
//用户的增加
@RequestMapping("/add")
public String add(){
System.out.println("UserController.add()");
//这里返回的是路径
//所以是需要删除ResponseBody
return "user/add";
}
//用户的更新
@RequestMapping("/update")
public String update(){
System.out.println("UserController.update()");
//同理返回路径
return "user/update";
}
//用户的的登录
@RequestMapping("/login")
public String login(){
System.out.println("UserController.login()");
//同理返回路径
return "login";
}
}
shrioConfig
package com.example.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;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
/**
* 创建Realm bean会让方法返回的对象放入到spring的环境,以便使用
*/
@Bean(name = "userRealm")
public UserRealm getRealm(){
return new UserRealm();
}
/**
* 创建DefaultWebSecurityManager
*/
//这里的传参有点特殊可以调用一个注解,这里有个细节,想看看注解区不区分大小写
//实测,会报错。。。所以是区分大小写的
// @Qualifier 注释指定注入 Bean 的名称,是用来消除歧义的
//这里也要有Bean
@Bean(name = "defaultWebSecurityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
//关联realm,并且这个是需要传参的
defaultWebSecurityManager.setRealm(userRealm);
return defaultWebSecurityManager;
//感觉和直接return一个 new的一样吧 之所以不直接return是因为,会调用一个
//关联realm的方法
}
/**
* 创建shiroFilterFactoryBean
*/
//也是需要注解和参数的
//这里也是需要bean注解的
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
//设置一个安全管理器来关联SecurityManager
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
//添加shiro内置过滤器
//先创建一个Map集合
Map<String,String> filterMap=new LinkedHashMap<String,String>();
//然后往里面添加东西
filterMap.put("/add","authc");
filterMap.put("/update","authc");
/**
* 修改调整的登录页面
*/
//然后这个跳转的页面,就是需要control来进行自动装入这个页面
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
}
这样就可以了