我们将使用 INI 文件为该简单应用程序配置 Shiro SecurityManager。首先,从pom.xml所在的目录创建一个 src/main/resources 目录。然后在新目录中创建一个shiro.ini文件,其内容如下:
# =============================================================================
# Tutorial INI configuration
#
# Usernames/passwords are based on the classic Mel Brooks' film "Spaceballs" :)
# =============================================================================
# -----------------------------------------------------------------------------
# Users and their (optional) assigned roles
# username = password, role1, role2, ..., roleN
# -----------------------------------------------------------------------------
[users]
root = secret, admin
guest = guest, guest
presidentskroob = 12345, president
darkhelmet = ludicrousspeed, darklord, schwartz
lonestarr = vespa, goodguy, schwartz
# -----------------------------------------------------------------------------
# Roles with assigned permissions
# roleName = perm1, perm2, ..., permN
# -----------------------------------------------------------------------------
[roles]
admin = *
schwartz = lightsaber:*
goodguy = winnebago:drive:eagle5
此配置基本上设置了一小组静态用户帐户,足以满足我们的第一个应用程序的需要。在后面的章节中,您将看到我们如何使用关系数据库,LDAP 和 ActiveDirectory 等更复杂的 User 数据源。
现在已经定义了一个 INI 文件,我们可以在 Tutorial 应用程序类中创建SecurityManager实例。更改main方法以反映以下更新:
public static void main(String[] args) {
log.info("My First Apache Shiro Application");
//1.
Factory
//2.
SecurityManager securityManager = factory.getInstance();
//3.
SecurityUtils.setSecurityManager(securityManager);
System.exit(0);
}
随意运行mvn compile exec:java并查看一切仍可成功运行(由于 Shiro 的默认调试日志记录或更低版本,您将看不到任何 Shiro 日志消息-如果它启动并运行无错误,则说明一切仍然正常)。
现在我们的 SecurityManager 已经设置好并且可以使用了,现在我们可以开始做我们 true 关心的事情了-执行安全操作。
🎯SpringBoot集成Shiro
😎准备工作
导入
Maven依赖thymeleaf
编写一个页面
index.html templates
首页
编写
controller
进行访问测试
package com.kuang.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class MyController {
@RequestMapping({"/","/index"})
public String toIndex(Model model){
model.addAttribute("msg","hello,Shiro");
return "index";
}
}
thymeleaf
😎整合Shiro
导入Shiro 和 spring整合的依赖
编写
Shiro
配置类 config包
package com.kuang.config;
import org.springframework.context.annotation.Configuration;
//声明为配置类
@Configuration
public class ShiroConfig {
//创建 ShiroFilterFactoryBean
//创建 DefaultWebSecurityManager
//创建 realm 对象
}
创建一个 realm 对象
package com.kuang.config;
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
public class UserRealm extends AuthorizingRealm {
//执行授权逻辑
@Override
protected AuthorizationInfo
doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("执行了=>授权逻辑PrincipalCollection");
return null;
}
//执行认证逻辑
@Override
protected AuthenticationInfo
doGetAuthenticationInfo(AuthenticationToken token) throws
AuthenticationException {
System.out.println("执行了=>认证逻辑AuthenticationToken");
return null;
}
}
将这个类注册到我们的Bean中! ShiroConfig
@Configuration
public class ShiroConfig {
//创建 ShiroFilterFactoryBean
//创建 DefaultWebSecurityManager
//创建 realm 对象
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
}
接下来我们该去创建 DefaultWebSecurityManager 了
//创建 DefaultWebSecurityManager
@Bean(name = "securityManager")
public DefaultWebSecurityManager
getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
DefaultWebSecurityManager securityManager = new
DefaultWebSecurityManager();
//关联Realm
securityManager.setRealm(userRealm);
return securityManager;
}
接下来我们该去创建 ShiroFilterFactoryBean 了
//创建 ShiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean
getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurity
Manager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new
ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
}
最后上完整的配置:
package com.kuang.config;
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 {
//创建 ShiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean
getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityMan
ager 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
public UserRealm userRealm(){
return new UserRealm();
}
}
😎页面拦截实现
跳转到页面的
controller
@RequestMapping("/user/add")
public String toAdd(){
return "user/add";
}
@RequestMapping("/user/update")
public String toUpdate(){
return "user/update";
}
添加Shiro的内置过滤器
@Bean
public ShiroFilterFactoryBean
getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurit
yManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new
ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
/*
添加Shiro内置过滤器,常用的有如下过滤器:
anon: 无需认证就可以访问
authc: 必须认证才可以访问
user: 如果使用了记住我功能就可以直接访问
perms: 拥有某个资源权限才可以访问
role: 拥有某个角色权限才可以访问
*/
Map
filterMap.put("/user/add","authc");
filterMap.put("/user/update","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
🎯登录认证操作
编写一个登录的
controller
//登录操作
@RequestMapping("/login")
public String login(String username,String password,Model model){
//使用shiro,编写认证操作
//1. 获取Subject
Subject subject = SecurityUtils.getSubject();
//2. 封装用户的数据
UsernamePasswordToken token = new UsernamePasswordToken(username,
password);
//3. 执行登录的方法,只要没有异常就代表登录成功!
try {
subject.login(token); //登录成功!返回首页
return "index";
} catch (UnknownAccountException e) { //用户名不存在
model.addAttribute("msg","用户名不存在");
return "login";
} catch (IncorrectCredentialsException e) { //密码错误
model.addAttribute("msg","密码错误");
return "login";
}
}
在
UserRealm
中编写用户认证的判断逻辑
//执行认证逻辑
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken
token) throws AuthenticationException {
System.out.println("执行了=>认证逻辑AuthenticationToken");
//假设数据库的用户名和密码
String name = "root";
String password = "123456";
//1.判断用户名
UsernamePasswordToken userToken = (UsernamePasswordToken)token;
if (!userToken.getUsername().equals(name)){
//用户名不存在
return null; //shiro底层就会抛出 UnknownAccountException
}
//2. 验证密码,我们可以使用一个AuthenticationInfo实现类
SimpleAuthenticationInfo
// shiro会自动帮我们验证!重点是第二个参数就是要验证的密码!
return new SimpleAuthenticationInfo("", password, "");
}
🎯整合数据库
导入
Mybatis
相关依赖
改造
UserRealm
,连接到数据库进行真实的操作!
//自定义Realm
public class UserRealm extends AuthorizingRealm {
@Autowired
UserService userService;
//执行授权逻辑
@Override
protected AuthorizationInfo
doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("执行了=>授权逻辑PrincipalCollection");
return null;
}
//执行认证逻辑
@Override
protected AuthenticationInfo
doGetAuthenticationInfo(AuthenticationToken token) throws
AuthenticationException {
System.out.println("执行了=>认证逻辑AuthenticationToken");
UsernamePasswordToken userToken = (UsernamePasswordToken)token;
//真实连接数据库
User user =
userService.queryUserByName(userToken.getUsername());
if (user==null){
//用户名不存在
return null; //shiro底层就会抛出 UnknownAccountException
}
return new SimpleAuthenticationInfo("", user.getPwd(), "");
}
}
🎯Shiro授权
在
UserRealm
中添加授权的逻辑,增加授权的字符串!
//执行授权逻辑
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection
principals) {
System.out.println("执行了=>授权逻辑PrincipalCollection");
//给资源进行授权
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//添加资源的授权字符串
info.addStringPermission("user:add");
return info;
}
我们再次登录测试,发现登录的用户是可以进行访问
add
页面了!授权成功!
🎯整合Thymeleaf
添加
Maven
的依赖;
配置一个
shiro
的
Dialect
,在
shiro
的配置中增加一个
Bean
//配置ShiroDialect:方言,用于 thymeleaf 和 shiro 标签配合使用
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
为了完美,我们在用户登录后应该把信息放到Session
中,我们完善下!在执行认证逻辑时候,加 入session
Subject subject = SecurityUtils.getSubject();
subject.getSession().setAttribute("loginUser",user);