一、授权
用户登录后,需要验证是否具有指定角色指定权限。Shiro也提供了方便的工具进行判断。
这个工具就是Realm的doGetAuthorizationInfo方法进行判断。触发权限判断的有两种
- 在页面中通过shiro:****属性判断
- 在接口服务中通过注解@Requires****进行判断
二、后端接口服务注解
通过给接口服务方法添加注解可以实现权限校验,可以加在控制器方法上,也可以加在业务方法上,一般加在控制器方法上。常用注解如下:
@RequiresAuthentication
验证用户是否登录,等同于方法subject.isAuthenticated()
@RequiresUser
验证用户是否被记忆;
登录认证成功subiect.isAuthenticated()为true
登录后被记忆subject.isRemembered()为true
@RequiresGuest
验证是否是一个guest的请求,是否是游客的请求
此时subject.getPrincipal()为null
@RequiresRoles
验证subject是否有相应角色,有角色访问方法,没有则会抛出异常AuthorizationException。
例如:@RequiresRoles( “aRoleName”)
void someMethod();
只有subject有aRoleName角色才能访问方法someMethod()
@RequiresPermissions
验证subject是否有相应权限,有权限访问方法,没有则会抛出异常AuthorizationException。
例如: @RequiresPermissions(“file:read”,“wite:aFile.txt”)
void someMethod() ;
subject必须同时含有file:read和wite:aFile.txt权限才能访问方法someMethod()
三、示例
3.1、沿用上一篇博客项目
3.2、添加数据库表
USE shirodb
CREATE TABLE role(
id BIGINT(20) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(30) DEFAULT NULL,
`desc` VARCHAR(50) DEFAULT NULL,
`realname` VARCHAR(20) DEFAULT NULL,
PRIMARY KEY(id)
)ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO role VALUES(1,'admin','所有权限','管理员');
INSERT INTO role VALUES(2,'userMag','用户管理权限','用户管理');
CREATE TABLE role_user(
id BIGINT(20) NOT NULL AUTO_INCREMENT,
uid BIGINT(20) DEFAULT NULL,
rid BIGINT(20) DEFAULT NULL,
PRIMARY KEY(id)
)ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
3.3、在main.html添加测试授权链接
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Shiro登录认证后主页面</h1>
<br>
登录用户为:<span th:text="${session.user}"></span>
<br>
<a href="/logout">登出</a>
<br>
<a href="/myController/userLoginRoles">测试授权</a>
</body>
</html>
3.4、在UserMapper中添加根据用户名查询角色名的方法
package com.massimo.shiro.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.massimo.shiro.entity.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserMapper extends BaseMapper<User> {
@Select("SELECT `name` FROM role WHERE id IN (\n" +
"\tSELECT rid FROM `role_user` WHERE uid=(\n" +
"\t\tSELECT id FROM `user` WHERE `name`=#{principal}\n" +
"\t)\n" +
")")
List<String> getUserRoleInfoMapper(@Param("principal")String principal);
}
3.5、UserService
package com.massimo.shiro.service;
import com.massimo.shiro.entity.User;
import java.util.List;
public interface UserService {
//用户登录
User getUserInfoByName(String name);
//根据用户查询角色信息
List<String> getUserRoleInfo(String principal);
}
3.6、UserServiceImpl
package com.massimo.shiro.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.massimo.shiro.entity.User;
import com.massimo.shiro.mapper.UserMapper;
import com.massimo.shiro.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User getUserInfoByName(String name) {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name",name);
User user = userMapper.selectOne(wrapper);
return user;
}
//根据用户查询角色信息
@Override
public List<String> getUserRoleInfo(String principal) {
return userMapper.getUserRoleInfoMapper(principal);
}
}
3.7、MyController
//登录认证角色
@RequiresRoles("admin")
@GetMapping("userLoginRoles")
@ResponseBody
public String userLoginRoles(){
System.out.println("登录验证角色");
return "验证角色成功!";
}
3.8、MyRealm
//自定义授权方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("自定义授权方法!");
//1.获取用户身份信息
String principal = principalCollection.getPrimaryPrincipal().toString();
//2.调用业务层获取用户的角色信息(从数据库)
List<String> roles = userService.getUserRoleInfo(principal);
System.out.println("当前用户角色信息" + roles);
//3.创建对象,封装当前登录用户的角色、权限信息
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRoles(roles);
//3.返回信息
return info;
}