作用:验证用户身份,用户访问权限控制
demo 实现-未连接数据库
引入依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.1</version>
</dependency>
测试之前准备
新建以下几个页面,主页,登录页,无权限页面,操作页面(add,update,select)。每个页面随便写点什么,主页写好跳转三个操作页面的路径


新建一个ShiroConfig 类
将add页面设置为不需要认证就可以访问,update设置为需要认证才可以进入
@Configuration
public class ShiroConfig {
//3.ShiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
filterFactoryBean.setSecurityManager(defaultWebSecurityManager);
//添加Shiro的内置过滤
/**
* anon:无需认证就可以访问
* authc:必须认证了才能访问
* user:必须拥有记住我的功能才能用
* perms:拥有对某个资源的权限才能访问
* role:拥有某个角色的权限才能访问
*/
Map<String,String> filterMap = new LinkedHashMap<>();
filterMap.put("/user/add","anon");
//需要拥有 user:update 权限才能进去
//如果未授权 会跳转到未授权页面
filterMap.put("/user/update","perms[user:update]");
filterMap.put("/user/select","perms[user:select]");
filterFactoryBean.setFilterChainDefinitionMap(filterMap);
//认证不通过去到登录页面
filterFactoryBean.setLoginUrl("/toLogin");
//未授权去到 未授权页面
filterFactoryBean.setUnauthorizedUrl("/toUnAuth");
return filterFactoryBean;
}
//2.DefaultWebSecurityManager
@Bean(name = "securityManager")
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联 userRealm
securityManager.setRealm(userRealm);
return securityManager;
}
//1.创建Realm 对象
@Bean(name = "userRealm")
public UserRealm userRealm(){
return new UserRealm();
}
}
新建一个UserRealm 用于进行权限信息的验证
认证
先实现认证,模拟从数据中读取数据
public class UserRealm extends AuthorizingRealm {
@Resource
UserMapper userMapper;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了---->授权");
return null;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了---->认证");
//用户登录数据 (模拟从数据库中获取)从数据库中获取
String name = "xmy";
String password = "12345";
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
if (!name.equals(userToken.getUsername())) {
return null; //UnknownAccountException
}
return new SimpleAuthenticationInfo("",password,"");
}
}
新建各个请求的跳转逻辑
@Controller
public class ShiroController {
@RequestMapping({"/","/index"})
public String toIndex(Model model){
model.addAttribute("msg","hello Shiro");
return "index";
}
@RequestMapping("/user/add")
public String add(){
return "/user/add";
}
@RequestMapping("/user/update")
public String update(){
return "/user/update";
}
@RequestMapping("/user/select")
public String select(){
return "/user/select";
}
@RequestMapping("/toLogin")
public String toLogin(){
return "login";
}
@RequestMapping("/login")
public String login(String username,String password,Model model){
//获取当前用户
Subject subject = SecurityUtils.getSubject();
//封装用户登陆数据
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
try{
subject.login(token); //执行登陆方法
return "/index";
}catch (UnknownAccountException e){
model.addAttribute("msg","用户名错误");
return "login";
}catch (IncorrectCredentialsException e){
model.addAttribute("msg","密码错误");
return "login";
}
}
@RequestMapping("/toUnAuth")
public String toUnAuth(){
return "unauth";
}
}
点击运行,出现的结果,用户xmy点击进入add页面无需任何认证就可以进入,点击update需要登录认证才可以进入

授权
分别将add,update请求改为当用户拥有add权限或者update权限才能进入该页面
filterMap.put("/user/add","perms[user:add]");
filterMap.put("/user/update","perms[user:update]");
在授权方法里面添加操作
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了---->授权");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//模拟从数据库读取权限
//手动设置一个权限
info.addStringPermission("user:update");
return info;
}
实现结果
当用户xmy进入add页面时需要认证登录,登录过后会被拦截,进入update页面,需要认证登录,登录过后不会被拦截可进入

demo 实现-连接数据库
引入连接数据库的相关依赖
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<!-- 自动生成代码需要 引入模板引擎 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.0</version>
</dependency>
<!--数据库相关-->
<!-- jdbc 依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- druid 依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.14</version>
</dependency>
新建数据库表(还需要建实体类以及mapper)
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`password` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`perms` varchar(255) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
配置文件连接数据库
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/springboot?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
username: root
password: root
initialSize: 1
minIdle: 3
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 30000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
# 打开 PSCache,并且指定每个连接上 PSCache 的大小
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
# 配置监控统计拦截的 filters,去掉后监控界面 SQL 无法统计,'wall' 用于防火墙
filters: stat,wall,slf4j
mybatis:
configuration:
map-underscore-to-camel-case: true
# 指定 mapper 文件的位置
mapper-locations: mapper/**/*Mapper.xml
# POJO 扫描包来让 MyBatis 自动扫描到自定义 POJO
type-aliases-package: com.example.domain
更改UserRealm类,数据从数据库中读取
数据库中,有两个用户一个拥有add权限,一个拥有update权限

登录,xmy用户可以进入add页面,不可以进入update页面,zhangsan用户可以进入update页面,不能进入add页面
public class UserRealm extends AuthorizingRealm {
@Resource
UserMapper userMapper;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了---->授权");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//模拟从数据库读取权限
//手动设置一个权限
//info.addStringPermission("user:update");
Subject subject = SecurityUtils.getSubject();
User currentUser = (User) subject.getPrincipal(); //获取认证时从数据库中读取出来的数据
info.addStringPermission(currentUser.getPerms());
return info;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了---->认证");
//用户登录数据 (模拟从数据库中获取)从数据库中获取
// String name = "xmy";
// String password = "12345";
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
// if (!name.equals(userToken.getUsername())) {
// return null; //UnknownAccountException
// }
//从真实数据库中获取
User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, userToken.getUsername()));
if (user == null){
return null; //UnknownAccountException
}
return new SimpleAuthenticationInfo(user,user.getPassword(),"");
}
}

本文介绍了Apache Shiro的快速入门教程,包括如何配置ShiroFilterFactoryBean,设置不同的访问权限,以及实现用户认证和授权。通过示例展示了如何在没有数据库连接的情况下设置权限控制,并逐步过渡到连接数据库后的权限验证。用户 Realm 的实现详细解释了认证和授权过程,最后演示了不同用户根据权限访问不同页面的效果。
498

被折叠的 条评论
为什么被折叠?



