本文内容:讲述Springboot 整合 Shiro 的相关步鄹、demo 实现以及 Shiro 与 Thymeleaf 的整合。
1
数据准备
新建数据库:hospital
新建数据表并添加测试数据:
dzm_his_member:{ uid 、user_name、password}
dzm_his_auth_rule :{ id、menu_name、title}
dzm_his_auth_group :{ id、title、rules}
其中,menu_name 为权限的具体执行方法,rules 为对应权限组的权限集合。
2
引入依赖
在 pom.xml 文件中引入 Shiro 的相关依赖:
<!-- shiro与spring整合依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!-- thymel对shiro的扩展坐标 -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
3
修改配置文件
在 application.properties 配置文件中添加连接数据库的相关信息:
# mysql
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/hospital?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.properties.hibernate.hbm2ddl.auto=update
4
编写数据库实体代码
使用代码生成器自动生成第一步中三个数据表对应的实体以及他们的Mapper 文件和 Service 文件。
5
配置Shiro
以下三个为Shiro的核心 API :
Subject: 用户主体(把操作交给SecurityManager)
SecurityManager:安全管理器(关联Realm)
Realm:Shiro连接数据的桥梁
ShiroConfig.java
@Configuration
public class ShiroConfig {
/**
* 创建ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加Shiro内置过滤器
/**
* Shiro内置过滤器,可以实现权限相关的拦截器
* 常用的过滤器:
* anon: 无需认证(登录)可以访问
* authc: 必须认证才可以访问
* user: 如果使用rememberMe的功能可以直接访问
* perms:该资源必须得到资源权限才可以访问
* role: 该资源必须得到角色权限才可以访问
*/
Map<String,String> filterMap = new LinkedHashMap<String,String>();
//放行login.html页面
filterMap.put("/login", "anon");
//授权过滤器
//注意:当前授权拦截后,shiro会自动跳转到未授权页面
filterMap.put("/add", "perms[user:add]");
filterMap.put("/update", "perms[user:update]");
filterMap.put("/*", "authc");
//修改调整的登录页面
shiroFilterFactoryBean.setLoginUrl("/");
//设置未授权提示页面
shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
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();
}
/**
* 配置ShiroDialect,用于thymeleaf和shiro标签配合使用
*/
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
}
UserRealm.java
public class UserRealm extends AuthorizingRealm{
@Autowired
private DzmHisMemberService memberService;
@Autowired
private DzmHisAuthGroupService authGroupService;
@Autowired
private DzmHisAuthRuleService authRuleService;
/**
* 执行授权逻辑
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
System.out.println("执行授权逻辑");
//给资源进行授权
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//添加资源的授权字符串
//info.addStringPermission("user:add");
//到数据库查询当前登录用户的授权字符串
//获取当前登录用户
Subject subject = SecurityUtils.getSubject();
DzmHisMember member = (DzmHisMember)subject.getPrincipal();
// 得到当前用户的权限类别
int typeById =member.getType();
System.out.println("1111111111111111111111111111111111111111111111111111111111111111111111111111111111");
System.out.println(typeById);
DzmHisAuthGroup authGroup=authGroupService.findById(typeById);
// 得到当前用户权限类别的具体权限序列
String rules=authGroup.getRules();
System.out.println("2222222222222222222222222222222222222222222222222222222222222222222222222222222222");
System.out.println(rules);
if (rules!=null || !rules.isEmpty()) {
// 拆分权限序列,得到具体权限
String[] ruleStrings=rules.split(",");
int id;
DzmHisAuthRule authRule;
String rule;
System.out.println("3333333333333333333333333333333333333333333333333333333333333333333333333333333333");
for (int i = 0; i < ruleStrings.length; i++) {
id=Integer.parseInt(ruleStrings[i]);
authRule=authRuleService.findById(id);
rule=authRule.getMenuName();
rule=rule.replace("/", ":");
info.addStringPermission(rule);
}
System.out.println();
}
try {
//不确定是什么原因导致权限可能会生成一个空值"", 会报错,所以将空值删除
if (info != null && info.getStringPermissions() != null) {
Set<String> permissions = info.getStringPermissions();
for (String permission : permissions) {
if (StringUtils.isEmpty(permission)) {
permissions.remove(permission);
}
}
}
} catch (Exception e) {
System.out.println("移除空值权限出错---"+e.getMessage());
}
return info;
}
/**
* 执行认证逻辑
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
System.out.println("执行认证逻辑");
//编写shiro判断逻辑,判断用户名和密码
//1.判断用户名
UsernamePasswordToken token = (UsernamePasswordToken)arg0;
DzmHisMember member = memberService.findByName(token.getUsername());
if(member==null){
//用户名不存在
return null;//shiro底层会抛出UnKnowAccountException
}
//2.判断密码
return new SimpleAuthenticationInfo(member,member.getPassword(),"");
}
}
6
Shiro 整合 Thymeleaf
测试:实现权限的动态显示,即根据用户权限集的不同显示不同的菜单
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>主页面</title>
</head>
<body>
<h3 th:text="${name}"></h3>
<hr/>
<div shiro:hasPermission="Doctor:index">
进入用户添加功能:<a href="add">用户添加</a><br/>
</div>
<div shiro:hasPermission="user:update">
进入用户更新功能:<a href="update">用户更新</a><br/>
</div>
<a href="login">登录</a>
</body>
</html>
7
编写控制器
loginController.java
@Controller
public class loginController {
@RequestMapping(value="/login",method = RequestMethod.GET)
public String toLogin() {
return "login";
}
@RequestMapping(value="/login",method = RequestMethod.POST)
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 "redirect:/toHome";
} catch (UnknownAccountException e) {
//登录失败:用户名不存在
model.addAttribute("msg", "用户名不存在");
return "login";
}catch (IncorrectCredentialsException e) {
//登录失败:密码错误
model.addAttribute("msg", "密码错误");
return "login";
}
}
@RequestMapping("/toHome")
public String toHome() {
return "home";
}
}
8
测试
在浏览器地址栏输入:
http://localhost:8080/hospital/login
进入登录页面,输入账号密码,验证通过后到达主菜单界面,显示当前用户所能看到的权限。
如:我的账号密码是 root 、root ,只有添加的权限而没有更新的权限,进入主界面之后应当只显示出添加的访问链接。
至此,本文结束。欢迎各位关注我的公众号:暗星涌动。