本篇文章小编给大家分享一下spring-shiro权限控制realm代码实例,文章代码介绍的很详细,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以来看看。
用户与角色实体
Role.java
@Data
@Entity
public class Role {
@Id
@GeneratedValue
private Integer id;
private Long userId;
private String role;
}
User.java
@Data
@Entity
public class User {
@Id
@GeneratedValue
private Long id;
private String username;
private String password;
}
Realm类
首先建立 Realm 类,继承自 AuthorizingRealm,自定义我们自己的授权和认证的方法。Realm 是可以访问特定于应用程序的安全性数据(如用户,角色和权限)的组件。
Realm.java
public class Realm extends AuthorizingRealm {
@Autowired
private UserService userService;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//从凭证中获得用户名
String username = (String) SecurityUtils.getSubject().getPrincipal();
//根据用户名查询用户对象
User user = userService.getUserByUserName(username);
//查询用户拥有的角色
List list = roleService.findByUserId(user.getId());
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
for (Role role : list) {
//赋予用户角色
info.addStringPermission(role.getRole());
}
return info;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//获得当前用户的用户名
String username = (String) authenticationToken.getPrincipal();
//从数据库中根据用户名查找用户
User user = userService.getUserByUserName(username);
if (userService.getUserByUserName(username) == null) {
throw new UnknownAccountException(
"没有在本系统中找到对应的用户信息。");
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(),getName());
return info;
}
}
Shiro 配置类
ShiroConfig.java
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map filterChainDefinitionMap = new LinkedHashMap();
//以下是过滤链,按顺序过滤,所以/**需要放最后
//开放的静态资源
filterChainDefinitionMap.put("/favicon.ico", "anon");//网站图标
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(myRealm());
return defaultWebSecurityManager;
}
@Bean
public MyRealm myRealm() {
MyRealm myRealm = new MyRealm();
return myRealm;
}
}
控制器
UserController.java
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/")
public String index() {
return "index";
}
@GetMapping("/login")
public String toLogin() {
return "login";
}
@GetMapping("/admin")
public String admin() {
return "admin";
}
@PostMapping("/login")
public String doLogin(String username, String password) {
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
Subject subject = SecurityUtils.getSubject();
try {
subject.login(token);
} catch (Exception e) {
e.printStackTrace();
}
return "redirect:admin";
}
@GetMapping("/home")
public String home() {
Subject subject = SecurityUtils.getSubject();
try {
subject.checkPermission("admin");
} catch (UnauthorizedException exception) {
System.out.println("没有足够的权限");
}
return "home";
}
@GetMapping("/logout")
public String logout() {
return "index";
}
}
Service
UserService.java
@Service
public class UserService {
@Autowired
private UserDao userDao;
public User getUserByUserName(String username) {
return userDao.findByUsername(username);
}
@RequiresRoles("admin")
public void send() {
System.out.println("我现在拥有角色admin,可以执行本条语句");
}
}
shiro权限不生效原因分析
shiro遇到的坑
-项目中使用shiro做登录校验和权限管理,在配置权限时遇到小坑,记录一下。
环境:springboot+freemarker+shiro
场景:后台管理,配置菜单以及按钮权限,分为三个层级,一二级暂时只考虑是否查看权限,第三层级为页面按钮权限,分增删改查。详情看图
问题:一二层级正常,第三层级权限不起作用!
权限标签定义如下:
开始怀疑是数据库没有录入,查看后权限标签与角色已对应,排除。
后面怀疑是页面问题,后面把第三层级标签与第一二层级同一页面,依然不起作用,排除。
后面怀疑是权限标签定义问题,把第三层级标签改为one:page1:data:add,奇迹出现,权限生效。证实权限标签定义出了问题。
问题原因:权限标签定义问题
但是后来想想为什么会出现这种问题,每个标签都是独一无二的,对此我对shiro对于权限标签的校验产生了兴趣,查看源码,一路debug后最终在org.apache.shiro.authz.permission中看到了关键所在,核心代码如下
//当这个方法返回true时说明有此权限
//这个p是代表当前循环匹配到的权限标签
public boolean implies(Permission p) {
// By default only supports comparisons with other WildcardPermissions
if (!(p instanceof WildcardPermission)) {
return false;
}
WildcardPermission wp = (WildcardPermission) p;
//把当前标签转分割成一个set集合(如one:page1:view:add 会分割成[[one], [page1], [view], [add]])
List> otherParts = wp.getParts();
int i = 0;
//循环匹配权限标签
for (Set otherPart : otherParts) {
// If this permission has less parts than the other permission, everything after the number of parts contained
// in this permission is automatically implied, so return true
//当全部循环匹配完没有返回false,则返回true,这个getparts()方法是获取当前角色当前循环的权限标签([[one], [page1], [view]])
if (getParts().size() - 1 < i) {
return true;
} else {
Set part = getParts().get(i);
/*如果包含有‘*'而且不包含当前分割后的标签则返回false,
*当用户可以查看页面,也就是说当前角色拥有one:page1:view标签
*这里【!part.contains(WILDCARD_TOKEN)】返回true,第二个【part.containsAll(otherPart)】one会跟当前标签匹**配one,
*也就是说这里全部循环完返回的都是false,所以最后都没true,于是在上面返回了一个true。
if (!part.contains(WILDCARD_TOKEN) && !part.containsAll(otherPart)) {
return false;
}
i++;
}
}