Apache Shiro,这一篇就够了

编程入门 行业动态 更新时间:2024-10-24 22:18:18

Apache Shiro,<a href=https://www.elefans.com/category/jswz/34/1768373.html style=这一篇就够了"/>

Apache Shiro,这一篇就够了

Apache Shiro,这一篇就够了

  • 1.Shiro实现登录拦截
  • 2.登录认证操作
  • 3.Shiro整合Mybatis
  • 4.用户授权操作
  • 5.Shiro授权
  • 6.Shiro整合Thymeleaf

1.Shiro实现登录拦截

前期环境准备

准备添加Shiro的内置过滤器:

@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {ShiroFilterFactoryBean subject = new ShiroFilterFactoryBean();// 设置安全管理器// 需要关联 securityManager ,通过参数把 securityManager 对象传递过来subject.setSecurityManager(defaultWebSecurityManager);/*添加Shiro内置过滤器,常用的有如下过滤器:anon: 无需认证就可以访问authc: 必须认证才可以访问user: 如果使用了记住我功能就可以直接访问perms: 拥有某个资源权限才可以访问role: 拥有某个角色权限才可以访问*/Map<String, String> filterMap = new LinkedHashMap<String, String>();filterMap.put("/user/add", "authc");filterMap.put("/user/update", "authc");subject.setFilterChainDefinitionMap(filterMap);return subject;
}

再次启动项目,拦截成功!

点击后会跳转到一个login.jsp页面,这个不是我们想要的效果,我们需要自己定义一个login页面!

我们编写一个自己的login页面:

<!DOCTYPE html>
<html lang="en" xmlns:th="">
<head><meta charset="UTF-8"><title>登录页面</title>
</head>
<body>
<h1>登录页面</h1>
<hr>
<form action=""><p>用户名: <input type="text" name="username"></p><p>密码: <input type="text" name="password"></p><p><input type="submit"></p>
</form>
</body>
</html>

编写跳转的controller:

@RequestMapping("/toLogin")
public String toLogin(){return "login";
}

在shiro中配置一下! ShiroFilterFactoryBean() 方法下面:

// 修改到要跳转的login页面;
subject.setLoginUrl("/toLogin");

再次测试,成功的跳转到了我们指定的Login页面!

另外,我们可以优化一下代码,拦截路径可以使用通配符来操作,更加简洁:

filterMap.put("/user/*","authc");

2.登录认证操作

编写一个登录的controller:

@RequestMapping("/login")
public String login(String username, String password, Model model) {// 使用shiro,编写认证操作// 1. 获取SubjectSubject subject = SecurityUtils.getSubject();// 2. 封装用户的数据UsernamePasswordToken token = new UsernamePasswordToken(username,password);// 3. 执行登录的方法,只要没有异常就代表登录成功!try {subject.login(token); // 登录成功!返回首页return "index";} catch (UnknownAccountException e) { // 用户名不存在model.addAttribute("msg", "用户名不存在");return "login";} catch (IncorrectCredentialsException e) { // 密码错误model.addAttribute("msg", "密码错误");return "login";}
}

接下来:

在前端修改对应的信息输出或者请求!

登录页面增加一个 msg 提示:

<p style="color:red;" th:text="${msg}"></p>

给表单增加一个提交地址:

<form th:action="@{/login}">

此时运行项目测试,成功执行了认证的模块:

现在,重要的来了,在 UserRealm 中编写用户认证的判断逻辑:

public class UserRealm extends AuthorizingRealm {@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {System.out.println("执行了授权方法");return null;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {String name = "admin";String password = "123456";UsernamePasswordToken userToken = (UsernamePasswordToken) token;// 用户名认证if (!userToken.getUsername().equals(name)) {// 用户名不存在// shiro底层就会抛出 UnknownAccountException异常return null;}/*密码认证验证密码,我们可以使用一个AuthenticationInfo实现类SimpleAuthenticationInfoshiro会自动帮我们验证!重点是第二个参数就是要验证的密码!*/return new SimpleAuthenticationInfo("", password, "");}
}

3.Shiro整合Mybatis

导入Mybatis相关依赖:

<!--  -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.12</version>
</dependency><!-- .mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.2</version>
</dependency><!-- .alibaba/druid -->
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.15</version>
</dependency><!--  -->
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency><!-- .projectlombok/lombok -->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version><scope>provided</scope>
</dependency>

编写配置文件 - 连接配置 application.yml

spring:datasource:username: rootpassword: rooturl: jdbc:mysql://localhost:3306/klza?useSSL=false&serverTimezone=GMT%2B8driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourceinitialSize: 5 # 初始化连接池大小minIdle: 5 # 最小值maxActive: 20 # 最大值maxWait: 60000  # 最长连接等待时间timeBetweenEvictionRunsMillis: 60000minEvictableIdleTimeMillis: 300000 # 连接保持空闲而不被驱逐的最长时间validationQuery: SELECT 1 FROM DUAL #用来检测连接是否有效的sqltestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsepoolPreparedStatements: true# 配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入# 如果允许报错,java.lang.ClassNotFoundException: org.apache.Log4j.Property# 则导入log4j 依赖就行filters: stat,wall,log4jmaxPoolPreparedStatementPerConnectionSize: 20useGlobalDataSourceStat: trueconnectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500# mybatis配置
mybatis:type-aliases-package: com.klza.pojo  # 实体类所在的包路径mapper-locations: classpath*:mapper/*.xml     # mybatis的映射文件所在的包路径    

编写实体类:(和数据库中的表字段要对应哦)

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {private int id;private String username;private String password;
}

编写Mapper接口:

@Repository
@Mapper
public interface UserMapper {User queryUserByName(String username);
}

编写Mapper配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis//DTD Mapper 3.0//EN"".dtd">
<mapper namespace="com.klza.mapper.UserMapper"><select id="queryUserByName" parameterType="String" resultType="User">select *from userwhere username = #{username}</select>
</mapper>

编写UserService 层:

接口:

public interface UserService {User queryUserByName(String name);
}

实现类:

@Service
public class UserServiceImpl implements UserService {@AutowiredUserMapper userMapper;@Overridepublic User queryUserByName(String name) {return userMapper.queryUserByName(name);}
}

测试一下数据库是否正常吧!

@SpringBootTest
class SpringBootShiroApplicationTests {@AutowiredUserServiceImpl userService;@Testvoid contextLoads() {User user = userService.queryUserByName("admin");System.out.println(user);// User(id=3, username=admin, password=123456)}
}

改造UserRealm,连接到数据库进行真实的操作!

public class UserRealm extends AuthorizingRealm {@AutowiredUserService userService;@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {System.out.println("执行了授权方法");return null;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {UsernamePasswordToken userToken = (UsernamePasswordToken) token;// 用户名认证User user = userService.queryUserByName(userToken.getUsername());if (user == null) {// 用户名不存在// shiro底层就会抛出 UnknownAccountException异常return null;}/*密码认证验证密码,我们可以使用一个AuthenticationInfo实现类SimpleAuthenticationInfoshiro会自动帮我们验证!重点是第二个参数就是要验证的密码!*/return new SimpleAuthenticationInfo("", user.getPassword(), "");}
}

重启项目测试成功!


4.用户授权操作

使用shiro的过滤器来拦截请求即可!

在 ShiroFilterFactoryBean 中添加一个过滤器,赋予权限访问机制:

// 授权过滤器
filterMap.put("/user/add","perms[user:admin]"); // 进入add页面需要有admin的权限!

我们再次启动测试一下,访问add,发现以下错误!未授权错误!

注意:当我们实现权限拦截后,shiro会自动跳转到未授权的页面,但我们没有这个页面,所以401 了🦠

配置一个未授权的提示的页面,增加一个controller提示:

@RequestMapping("/noauth")
@ResponseBody
public String noAuth() {return "未经授权不能访问此页面";
}

然后在 shiroFilterFactoryBean 中配置一个未授权的请求页面!

// 配置未授权的跳转页面
subject.setUnauthorizedUrl("/noauth");

测试启动,成功!


5.Shiro授权

想要实现不同用户的权限访问,需要在数据库中新增perms字段,标识每一个用户的权限:

例如:

之后对应更新pojo类!

在UserRealm 中添加授权的逻辑,增加授权的字符串!

@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {System.out.println("执行了授权方法");// 给资源进行授权SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();Subject subject = SecurityUtils.getSubject(); // 获得当前对象User currentUser = (User) subject.getPrincipal(); // 拿到User对象info.addStringPermission(currentUser.getPerms()); // 设置权限return info;
}

之后注意,认证的返回值的第一个参数要为user:

return new SimpleAuthenticationInfo(user, user.getPassword(), "");

授权成功!


6.Shiro整合Thymeleaf

我们想根据权限展示不同的前端页面,没有对应权限的用户登录不显示前端内容,这就需要实现一个Shiro整合Thymeleaf:

添加Maven的依赖:

<!-- .github.theborakompanioni/thymeleaf-extras-shiro -->
<dependency><groupId>com.github.theborakompanioni</groupId><artifactId>thymeleaf-extras-shiro</artifactId><version>2.1.0</version>
</dependency>

配置一个shiro的Dialect ,在shiro的配置中增加一个Bean:

/*** 整合Thymeleaf用到的bean* @return*/
@Bean
public ShiroDialect getShiroDialect(){return new ShiroDialect();
}

修改前端的配置:

导入命名空间:

xmlns:shiro=""

修改index.html的代码:

<div shiro:notAuthenticated><a th:href="@{/toLogin}">登录</a>
</div>
<div shiro:hasPermission="user:admin"><a th:href="@{/user/add}">add</a>
</div>
<div><a th:href="@{/user/update}">update</a>
</div>

重启项目测试成功!

更多推荐

Apache Shiro,这一篇就够了

本文发布于:2024-02-11 19:27:23,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1682924.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:这一   就够了   Apache   Shiro

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!