复习

  1. 日志框架
    1. 作用
      1. 定位问题(debug、异常、出参入参)
      2. 跟踪执行流程
      3. 统计数据
    2. 如何打日志
      1. 位置
        1. controller,入口,整个系统的入口,意味着,用户输入的参数
        2. 异常
        3. 业务的关键位置
      2. 级别
        1. trace 追踪
        2. debug 调试
        3. info 信息
        4. warn 警告 业务异常
        5. error 错误 系统异常
    3. spring-boot自带日志框架slf4j+logback,设置日志级别 logging.level.xxx=info
      1. api使用
        1. 占位符 {}
        2. 异常输出 log.error(“错误信息”,exception);
    4. 常用日志框架
      1. jul
      2. log4j
      3. slf4j(接口)+logback(实现)
      4. log4j2
  2. 安全框架Shiro
    1. 主要功能
      1. 认证 authentication authc
      2. 授权 authorization authz
      3. 会话管理
      4. 加密
      5. 缓存
    2. shiro示例
      1. Subject 门面/接口 当前用户
        1. login 登录
        2. logout 登出
        3. isPermitted 是否权限
        4. hasRole 是否有角色
      2. SecurityManager 安全管理器,执行认证授权的操作
      3. UsernamePasswordToken extends AuthenticationToken
    3. shiro调用流程

应用 —-> Subject

SecurityManager

Realm 提供数据源

DB
d. RBAC : Role-Based-Access Control基于角色的权限控制

  • 用户
  • 用户角色表
  • 角色
  • 角色权限表
  • 权限

e. 自定义Realm

  • 继承AuthorizingRealm
  • doGetAuthenticationInfo
    • -> AuthenticationToken
    • <- AuthenticationInfo
  • doGetAuthorizationInfo
    • -> PrincipalCollection
    • <- AuthorizationInfo

继承体系(ctrl+h)
Realm
AuthenticationToken
AuthenticationInfo

异常体系
ShiroException
CacheException
SessionException
AuthenticationException 认证异常
AccountException 账户异常
DisabledAccountException 账户禁用异常
LockedAccountException 账户锁定异常
ConcurrentAccessException 并发访问异常
ExcessiveAttemptsException 尝试次数超限
UnknownAccountException 未知账户异常
CredenctialsException 密码异常
UnSupportedTokenException 不支持的token
AuthorizationException

Shiro集成到spring-boot

sihro集成到web环境下
web环境下的资源:

  • 不登录也可以访问
  • 登录可以访问
  • 登录且必须有相应权限才可以访问

web环境下,将资源近似看做网址
shiro需要检查每一个请求,确定是否需要登录,或者是否需要指定的权限
image.png

  1. 添加shiro-spring-boot-starter依赖

    1. <dependency>
    2. <groupId>org.apache.shiro</groupId>
    3. <artifactId>shiro-spring-boot-web-starter</artifactId>
    4. <version>1.4.1</version>
    5. </dependency>
  2. 修改配置文件

    1. shiro:
    2. loginUrl: /login.html
  3. 配置自定义Realm

    1. 删除掉mybatis,换用注入的UserMapper
    2. 在配置类中注册自定Realm
  4. 配置shiro过滤器链 ```java package com.example.demo56.config;

import com.example.demo56.component.MyRealm; import org.apache.shiro.realm.Realm; import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition; import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;

import java.util.Map;

@Configuration public class ShiroConfig {

  1. //shiro自定义Realm
  2. @Bean
  3. public Realm myRealm(){
  4. MyRealm myRealm = new MyRealm();
  5. return myRealm;
  6. }
  7. //shiro过滤器链的配置
  8. // /login ->不需要登录即可访问
  9. // /order ->必须登录才可以访问
  10. @Bean
  11. public ShiroFilterChainDefinition shiroFilterChainDefinition(){
  12. ShiroFilterChainDefinition sfcd = new DefaultShiroFilterChainDefinition();
  13. Map<String, String> filterChainMap = sfcd.getFilterChainMap();
  14. //路径 <-> 过滤器的配置缩写
  15. filterChainMap.put("/login","anon");// 使用anon对应的过滤器,过滤/login请求,实质上就放行
  16. filterChainMap.put("/login.html","anon");
  17. filterChainMap.put("/images/**","anon");
  18. filterChainMap.put("/js/**","anon");
  19. filterChainMap.put("/css/**","anon");
  20. filterChainMap.put("/logout","logout");
  21. filterChainMap.put("/**","user");
  22. return sfcd;
  23. }

}

  1. 5. 编写登录代码
  2. ```java
  3. //前端
  4. 登录
  5. <form action="/login" method="post">
  6. <input type="text" name="username" id="username" placeholder="请输入用户名">
  7. <input type="password" name="password" id="password" placeholder="请输入密码">
  8. <input type="submit" value="登录"/>
  9. </form>
  10. //后端
  11. @PostMapping("/login")
  12. public Result login(LoginForm loginForm){
  13. log.info("进入登录{}",loginForm);
  14. Subject subject = SecurityUtils.getSubject();
  15. try {
  16. subject.login(new UsernamePasswordToken(loginForm.getUsername(), loginForm.getPassword()));
  17. return Result.success(subject.getPrincipal());
  18. }catch (AuthenticationException e){
  19. log.info("登录失败",e);
  20. return Result.fail("登录失败:"+e.getMessage());
  21. }
  22. }
配置缩写 对应的过滤器 功能
*anon AnonymousFilter 指定url可以匿名访问
authc FormAuthenticationFilter 指定url需要form表单登录,默认会从请求中获取username、password,``rememberMe等参数并尝试登录,如果登录不了就会跳转到loginUrl配置的路径。我们也可以用这个过滤器做默认的登录逻辑,但是一般都是我们自己在控制器写登录逻辑的,自己写的话出错返回的信息都可以定制嘛。
authcBasic BasicHttpAuthenticationFilter 指定url需要basic登录
*logout LogoutFilter 登出过滤器,配置指定url就可以实现退出功能,非常方便
noSessionCreation NoSessionCreationFilter 禁止创建会话
perms PermissionsAuthorizationFilter 需要指定权限才能访问
port PortFilter 需要指定端口才能访问
rest HttpMethodPermissionFilter 将http请求方法转化成相应的动词来构造一个权限字符串,这个感觉意义不大,有兴趣自己看源码的注释
roles RolesAuthorizationFilter 需要指定角色才能访问
ssl SslFilter 需要https请求才能访问
*user UserFilter 需要已登录或“记住我”的用户才能访问

授权

注解 ,在需要的方法上添加注解
RequiresAuthentication
RequiresGuest
RequiresPermissions
RequiresRoles
RequiresUser

  1. @GetMapping("/testAuthz")
  2. @RequiresRoles("dev_mgr")
  3. public String testAuthz(){
  4. return "success";
  5. }
  6. @GetMapping("/testAuthz2")
  7. @RequiresPermissions("code:repo:create")
  8. public String testAuthz2(){
  9. return "success";
  10. }

缓存

存在速度较快的介质中,一般是内存
将部分经常被查询的数据,存储在内存中,加快查询速度
查询时,先查询缓存,若无,则查询数据库,并将结果缓存

优点: 加快查询;
缺点:消耗内存;数据不一致问题(加过期时间;更新数据时同步更新缓存)
适用场景:查远多于改;查询频率较高;

授权场景非常适用缓存

  1. //shiro自定义Realm
  2. @Bean
  3. public Realm myRealm(){
  4. MyRealm myRealm = new MyRealm();
  5. myRealm.setCacheManager(cacheManager());
  6. myRealm.setAuthenticationCachingEnabled(true);
  7. myRealm.setAuthorizationCachingEnabled(true);
  8. return myRealm;
  9. }
  10. @Bean
  11. public MemoryConstrainedCacheManager cacheManager(){
  12. return new MemoryConstrainedCacheManager();
  13. }

加密

密码密文存储

  1. 注册:插入数据库时,需要加密存储
  2. 登录:对用户输入的数据进行加密,与数据库中的密文比对

步骤:

  1. 新建一个EncryptUtil,修改数据库密码为密文 ```java package com.example.demo56.common;

import org.apache.shiro.crypto.hash.SimpleHash;

public class EncryptUtil { //加密算法 public static final String ALGORITHM_NAME=”SHA-256”; //迭代次数 public static final int ITERATIONS=1;

  1. public static String encrypt(String source){
  2. //创建一个hash工具,设置了算法及原始数据
  3. SimpleHash simpleHash = new SimpleHash(ALGORITHM_NAME,source);
  4. //设置迭代次数
  5. simpleHash.setIterations(ITERATIONS);
  6. //转换为16进制
  7. return simpleHash.toHex();
  8. }

}

  1. 2. 注册一个HashedCredentialsMatcher
  2. ```java
  3. @Bean
  4. public CredentialsMatcher hashedCredentialMatcher(){
  5. HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(EncryptUtil.ALGORITHM_NAME);
  6. credentialsMatcher.setHashIterations(EncryptUtil.ITERATIONS);
  7. return credentialsMatcher;
  8. }
  9. //shiro自定义Realm
  10. @Bean
  11. public Realm myRealm(){
  12. MyRealm myRealm = new MyRealm();
  13. myRealm.setCacheManager(cacheManager());
  14. myRealm.setAuthenticationCachingEnabled(true);
  15. myRealm.setAuthorizationCachingEnabled(true);
  16. //设置密码比较器
  17. myRealm.setCredentialsMatcher(hashedCredentialMatcher());
  18. return myRealm;
  19. }
  1. 测试

集成Thymeleaf

后端模板引擎

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-thymeleaf</artifactId>
  4. </dependency>
  5. <!--集成shiro到thymeleaf-->
  6. <dependency>
  7. <groupId>com.github.theborakompanioni</groupId>
  8. <artifactId>thymeleaf-extras-shiro</artifactId>
  9. <version>2.0.0</version>
  10. </dependency>
  1. package com.example.demo56.controller;
  2. import org.apache.shiro.SecurityUtils;
  3. import org.springframework.stereotype.Controller;
  4. import org.springframework.ui.ModelMap;
  5. import org.springframework.web.bind.annotation.GetMapping;
  6. @Controller
  7. public class ThymeleafShiroController {
  8. @GetMapping("toPage")
  9. public String toPage(ModelMap modelMap){
  10. modelMap.put("user", SecurityUtils.getSubject().getPrincipal());
  11. return "success";
  12. }
  13. }
  1. @Bean("shiroDialect")
  2. public ShiroDialect getShiroDialect(){
  3. return new ShiroDialect();
  4. }
  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>ThymeleafShiro</title>
  6. </head>
  7. <body>
  8. <div>
  9. 您好 <span shiro:guest="">游客</span> <span shiro:authenticated="" th:text="${user.username}"></span>
  10. </div>
  11. <div >
  12. <a shiro:hasRole="dev_mgr" href="/fire/developer">开除开发人员</a>
  13. </div>
  14. <div shiro:hasPermission="code:repo:create">
  15. <a href="/core/repo/create">创建代码库</a>
  16. </div>
  17. <div shiro:hasPermission="keepclean">
  18. <a href="/isClean">保洁完成</a>
  19. </div>
  20. </body>
  21. </html>

官方github: https://github.com/theborakompanioni/thymeleaf-extras-shiro#tags

作业

  1. 讲师管理[后台]

1)提供建表sql
2)spring-boot+mybatis-plus+shiro后端代码,不需要前端

  1. 讲师入驻
  2. 讲师带条件的分页查询(姓名,状态[是否审核])
  3. 审核通过/不通过
  4. 开除

image.png