基于springboot注解的shiro 授权及角色认证

目录

授权

后端接口服务注解

授权验证-没有角色无法访问

授权验证-获取角色进行验证 

授权验证-获取权限进行验证

授权验证-异常处理


授权

用户登录后,需要验证是否具有指定角色指定权限。Shiro也提供了方便的工具进行判 断。 这个工具就是Realm的doGetAuthorizationInfo方法进行判断。

触发权限判断的有两种 方式

(1) 在页面中通过shiro:****属性判断

(2) 在接口服务中通过注解@Requires****进行判断

后端接口服务注解

通过给接口服务方法添加注解可以实现权限校验,可以加在控制器方法上,也可以加 在业务方法上,一般加在控制器方法上。常用注解如下:

(1)@RequiresAuthentication

验证用户是否登录,等同于方法subject.isAuthenticated()

(2)@RequiresUser

验证用户是否被记忆: 登录认证成功subject.isAuthenticated()为true 登录后被记忆subject.isRemembered()为true

(3)@RequiresGuest

验证是否是一个guest的请求,是否是游客的请求 此时subject.getPrincipal()为null

(4)@RequiresRoles

验证subject是否有相应角色,有角色访问方法,没有则会抛出异常 AuthorizationException。 例如:

@RequiresRoles(“aRoleName”)

void someMethod();

只有subject有aRoleName角色才能访问方法someMethod()

(5)@RequiresPermissions

验证subject是否有相应权限,有权限访问方法,没有则会抛出异常 AuthorizationException。 例如:

@RequiresPermissions (“file:read”,”wite:aFile.txt”)

void someMethod();

subject必须同时含有file:read和wite:aFile.txt权限才能访问方法someMethod()

授权验证-没有角色无法访问

(1)添加 controller 方法,并添加验证角色注解 


//登录认证验证角色 
@RequiresRoles("admin") 
@GetMapping("userLoginRoles") 
@ResponseBody 
public String userLoginRoles() { 
 System.out.println("登录认证验证角色"); 
 return "验证角色成功"; 
}

(2)修改 main.html

<body> 
 <h1>Shiro 登录认证后主页面</h1> 
 <br> 
 登录用户为:<span th:text="${session.user}"></span> 
 <br> 
 <a href="/logout">登出</a> 
<br> 
 <a href="/myController/userLoginRoles">测试授权</a> 
</body>

(3)修改 MyRealm 方法

//自定义授权方法:获取当前登录用户权限信息,返回给 Shiro 用来进行授权对比 
@Override 
protected AuthorizationInfo 
doGetAuthorizationInfo(PrincipalCollection principalCollection) { 
 System.out.println("进入自定义授权方法"); 
 return null; 
} 

(4)运行测试

授权验证-获取角色进行验证 

(1)修改 MyRealm 方法 

//自定义授权方法:获取当前登录用户权限信息,返回给 Shiro 用来进行授权对比 
@Override 
protected AuthorizationInfo 
doGetAuthorizationInfo(PrincipalCollection principalCollection) { 
 System.out.println("进入自定义授权方法"); 
 //1 创建对象,存储当前登录的用户的权限和角色 
 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); 
 //2 存储角色 
 info.addRole("admin"); 
 //返回 
 return info; 
} 

(2)运行测试

 (3)确认库表

CREATE TABLE `role` ( 
 `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号', 
 `name` VARCHAR(30) DEFAULT NULL COMMENT '角色名', 
 `desc` VARCHAR(50) DEFAULT NULL COMMENT '描述', 
 `realname` VARCHAR(20) DEFAULT NULL COMMENT '角色显示名', 
 PRIMARY KEY (`id`) 
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='角色表'; 

CREATE TABLE `role_user` ( 
 `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号', 
 `uid` BIGINT(20) DEFAULT NULL COMMENT '用户 id', 
 `rid` BIGINT(20) DEFAULT NULL COMMENT '角色 id', 
 PRIMARY KEY (`id`) 
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='角色用户映射表'; 

 (4)查询 sql 根据用户名查询对应角色信息

SELECT NAME FROM role WHERE id IN (SELECT rid FROM role_user WHERE uid=(SELECT id FROM USER WHERE NAME='张三'));

 (5)mapper 方法

@Repository 
public interface UserMapper extends BaseMapper<User> { 
 @Select("SELECT NAME FROM role WHERE id IN (SELECT rid FROM 
role_user WHERE uid=(SELECT id FROM USER WHERE NAME=#{principal}))") 
 List<String> getUserRoleInfoMapper(@Param("principal") String 
principal); 
}

(6)service 实现

//获取用户的角色信息 
@Override 
public List<String> getUserRoleInfo(String principal) { 
 return userMapper.getUserRoleInfoMapper(principal); 
} 

 (7)MyRealm 方法改造

//自定义授权方法:获取当前登录用户权限信息,返回给 Shiro 用来进行授权对比 
@Override 
protected AuthorizationInfo 
doGetAuthorizationInfo(PrincipalCollection principalCollection) { 
 System.out.println("进入自定义授权方法"); 
 //获取当前用户身份信息 
 String principal = 
principalCollection.getPrimaryPrincipal().toString(); 
 //调用接口方法获取用户的角色信息 
 List<String> roles = userService.getUserRoleInfo(principal); 
 System.out.println("当前用户角色信息:"+roles); 
 //创建对象,存储当前登录的用户的权限和角色 
 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); 
 //存储角色 
 info.addRoles(roles); 
 //返回 
 return info; 
} 

(8)启动登录测试

授权验证-获取权限进行验证

获取权限验证和获取角色相类似

(1)确认库表

CREATE TABLE `permissions` ( 
 `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号', 
 `name` VARCHAR(30) DEFAULT NULL COMMENT '权限名', 
 `info` VARCHAR(30) DEFAULT NULL COMMENT '权限信息', 
 `desc` VARCHAR(50) DEFAULT NULL COMMENT '描述', 
 PRIMARY KEY (`id`) 
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='权限表';

CREATE TABLE `role_ps` ( 
 `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号', 
 `rid` BIGINT(20) DEFAULT NULL COMMENT '角色 id', 
 `pid` BIGINT(20) DEFAULT NULL COMMENT '权限 id', 
 PRIMARY KEY (`id`) 
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='角色权限映射表`

 

(2)查询 sql 根据角色名查询对应权限信息

SELECT info FROM permissions WHERE id IN (SELECT pid FROM role_ps WHERE rid IN (SELECT id FROM role WHERE NAME IN('admin','userMag')));

(3)mapper 方法

@Select({ 
 "<script>", 
 "select info FROM permissions WHERE id IN ", 
 "(SELECT pid FROM role_ps WHERE rid IN (", 
 "SELECT id FROM role WHERE NAME IN ", 
 "<foreach collection='roles' item='name' open='(' 
separator=',' close=')'>", 
 "#{name}", 
 "</foreach>", 
 "))", 
 "</script>" 
}) 
List<String> getUserPermissionInfoMapper(@Param("roles")List<String> 
roles);

 (4)service 实现

//获取用户角色的权限信息 
@Override 
public List<String> getUserPermissionInfo(List<String> roles) { 
 return userMapper.getUserPermissionInfoMapper(roles); 
}

(5)MyRealm 方法改造

//自定义授权方法:获取当前登录用户权限信息,返回给 Shiro 用来进行授权对比 
@Override 
protected AuthorizationInfo 
doGetAuthorizationInfo(PrincipalCollection principalCollection) { 
 System.out.println("进入自定义授权方法"); 
 //获取当前用户身份信息 
 String principal = 
principalCollection.getPrimaryPrincipal().toString(); 
 //调用接口方法获取用户的角色信息 
 List<String> roles = userService.getUserRoleInfo(principal); 
 System.out.println("当前用户角色信息:"+roles); 
 //调用接口方法获取用户角色的权限信息 
 List<String> permissions = 

userService.getUserPermissionInfo(roles); 
 System.out.println("当前用户权限信息:"+permissions); 
 //创建对象,存储当前登录的用户的权限和角色 
 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); 
 //存储角色 
 info.addRoles(roles); 
 //存储权限信息 
 info.addStringPermissions(permissions); 
 //返回 
 return info; 
}

(6)添加 controller 方法

//登录认证验证权限 
@RequiresPermissions("user:delete") 
@GetMapping("userPermissions") 
@ResponseBody 
public String userLoginPermissions() { 
 System.out.println("登录认证验证权限"); 
 return "验证权限成功"; 
}

(7)改造 main.html

<body> 
 <h1>Shiro 登录认证后主页面</h1> 
 <br> 
 登录用户为:<span th:text="${session.user}"></span> 
 <br> 
 <a href="/logout">登出</a> 
 <br> 
 <a href="/myController/userLoginRoles">测试授权-角色验证</a> 
 <br> 
 <a href="/myController/userPermissions">测试授权-权限验证</a> 
</body> 

 (8)启动登录测试

授权验证-异常处理

(1)创建认证异常处理类,使用@ControllerAdvice 加@ExceptionHandler 实现特殊异 常处理。

@ControllerAdvice 
public class PermissionsException { 
 @ResponseBody 
 @ExceptionHandler(UnauthorizedException.class) 
 public String unauthorizedException(Exception ex){ 
 return "无权限"; 
 } 
 
 @ResponseBody 
 @ExceptionHandler(AuthorizationException.class) 
 public String authorizationException(Exception ex){ 
 return "权限认证失败"; 
 } 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
【资源说明】 1、基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 2、该资源包括项目的全部源码,下载可以直接使用! 3、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设项目,作为参考资料学习借鉴。 4、本资源作为“参考资料”如果需要实现其他功能,需要能看懂代码,并且热爱钻研,自行调试。 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip
Spring Boot项目中使用Shiro进行安全控制,需要进行以下几个步骤。 1. 引入ShiroSpring Boot相关依赖 在`pom.xml`文件中添加以下依赖: ```xml <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.6.0</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.6.0</version> </dependency> ``` 2. 配置Shiro的安全管理器 在Spring Boot的配置文件中,添加Shiro的相关配置: ```yaml # Shiro配置 shiro: # 配置安全管理器 securityManager: # 配置Realm realms: - name: myRealm # 配置自定义的Realm实现类 customRealm: com.example.demo.shiro.MyRealm # 配置Session管理器 sessionManager: # Session过期时间,单位:毫秒 globalSessionTimeout: 1800000 # 配置Cookie cookie: # Cookie名称 name: SHIROSESSIONID # Cookie过期时间,单位:秒 maxAge: 1800 # Cookie路径 path: / # 配置Shiro Filter filters: # 配置自定义的Filter实现类 myFilter: com.example.demo.shiro.MyFilter # 配置Filter Chain filterChainDefinitions: # 配置访问控制规则 /login: anon /logout: logout /**: myFilter ``` 其中,配置了安全管理器`securityManager`,包括了自定义的Realm实现类`MyRealm`、Session管理器和Cookie。 配置了Shiro Filter`myFilter`,以及Filter Chain,其中`/login`可以匿名访问,`/logout`需要进行登出操作,其他URL需要经过自定义的Filter`MyFilter`进行访问控制。 3. 实现自定义Realm 在`MyRealm`类中,需要实现Shiro的`Realm`接口,重写`doGetAuthenticationInfo`和`doGetAuthorizationInfo`方法,完成身份认证授权。 ```java public class MyRealm extends AuthorizingRealm { /** * 身份认证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { // 获取用户名和密码 String username = (String) authenticationToken.getPrincipal(); String password = new String((char[]) authenticationToken.getCredentials()); // 根据用户名查询用户信息 User user = userService.findByUsername(username); // 判断用户是否存在 if (user == null) { throw new UnknownAccountException("用户不存在"); } // 判断密码是否正确 if (!password.equals(user.getPassword())) { throw new IncorrectCredentialsException("密码错误"); } // 将用户信息封装到AuthenticationInfo中 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, password, getName()); return authenticationInfo; } /** * 授权 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { // 获取用户信息 User user = (User) principalCollection.getPrimaryPrincipal(); // 查询用户角色权限信息 List<Role> roles = roleService.findByUserId(user.getId()); List<Permission> permissions = permissionService.findByUserId(user.getId()); // 封装角色权限信息到AuthorizationInfo中 SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); for (Role role : roles) { authorizationInfo.addRole(role.getName()); } for (Permission permission : permissions) { authorizationInfo.addStringPermission(permission.getName()); } return authorizationInfo; } } ``` 4. 实现自定义Filter 在`MyFilter`类中,需要继承Shiro的`AccessControlFilter`类,重写`isAccessAllowed`和`onAccessDenied`方法,完成访问控制逻辑。 ```java public class MyFilter extends AccessControlFilter { @Override protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception { // 获取Shiro的Subject对象 Subject subject = getSubject(servletRequest, servletResponse); // 判断是否已经登录 if (subject.isAuthenticated()) { return true; } // 判断是否是登录请求 HttpServletRequest request = (HttpServletRequest) servletRequest; if ("/login".equals(request.getServletPath())) { return true; } // 其他情况都要进行跳转到登录页面 redirectToLogin(servletRequest, servletResponse); return false; } @Override protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception { // 如果是Ajax请求,则返回JSON格式的数据 HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; if (request.getHeader("X-Requested-With") != null && request.getHeader("X-Requested-With").equalsIgnoreCase("XMLHttpRequest")) { response.setContentType("application/json;charset=UTF-8"); response.getWriter().write(JSON.toJSONString(Result.fail("未登录或登录超时"))); } else { // 否则进行跳转到登录页面 redirectToLogin(servletRequest, servletResponse); } return false; } } ``` 5. 配置Shiro注解支持 在Spring Boot的配置类中,添加`@EnableAspectJAutoProxy(proxyTargetClass = true)`注解和`@EnableAuthorization`注解,启用Shiro注解支持和AOP功能。 ```java @Configuration @EnableAspectJAutoProxy(proxyTargetClass = true) @EnableAuthorization public class ShiroConfig { // ... } ``` 至此,基于Shiro的安全控制已经配置完成。在需要进行访问控制的Controller方法上,添加相应的注解即可完成授权操作,例如`@RequiresPermissions("user:view")`表示需要拥有`user:view`权限才能访问该方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个风轻云淡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值