Java学习_第四阶段

本文介绍了Shiro框架在认证、加密和权限管理方面的应用,包括用户登录流程、自定义Realm实现、加密算法配置、权限分类及数据库表设计。同时,文章探讨了JWT令牌的安全验证,前端如何获取与使用token,以及Redis的配置和基础使用,如缓存、验证码等。

day(3-22日)shiro框架的应用

1、认证

知识点补充

认证方式:用户+密码
  • 1.2、shiro的步骤以及关键

    • 1、添加依赖
     <dependency>
         <groupId>org.apache.shiro</groupId>
       <artifactId>shiro-spring-boot-web-starter</artifactId>
         <version>1.8.0</version>
    </dependency>
    
    • 2、控制层

      UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);会将这个对象传递给自定义并且继承AuthenticatingRealm类

      @PostMapping("/login")
          public String login(String username, String password) {
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
              try {
                  SecurityUtils.getSubject().login(usernamePasswordToken);//将corller层的数据传到token
              } catch (UnknownAccountException uae) {
                  
              } catch (LockedAccountException lae) {
              }
              return "";
        }
      
    • 3、配置类

      • 配置路径拦截器
      • 自定义继承类继承不同的类

      认证 、密码加密 AuthenticatingRealm 抽象* 授权

      • 权限 AuthorizingRealm

      • 配置拦截器

      • 一开始所有的默认拦截所有的请求

      • anon 不需要认证的
        authc 其他所有都需要认证
        
      
      
      
      
      
      
      
      
          @Bean("filterChainDefinition")
          public ShiroFilterChainDefinition filterChainDefinition() {
              DefaultShiroFilterChainDefinition shiroFilterChainDefinition = new DefaultShiroFilterChainDefinition();
              /**
               * 不需要认证的
               */
              shiroFilterChainDefinition.addPathDefinition("/login", "anon");
              shiroFilterChainDefinition.addPathDefinition("/register", "anon");
      //        shiroFilterChainDefinition.addPathDefinition("/druid/**", "anon");
      
              // 其他所有都需要认证
              shiroFilterChainDefinition.addPathDefinition("/**", "authc");
              return shiroFilterChainDefinition;
          }
      
    • 1.3自定义配置类(继承AuthenticatingRealm抽象类)

      认证 、加密 AuthenticatingRealm 抽象* 授权

      权限 AuthorizingRealm

      • a、doGetAuthenticationInfo来进行权限的验证并从前端获取数据(前端获取数据)

         @Override
            protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
                /**
                 * 1 获取客服端传递过来的用户名
                 */
                String username = (String) authenticationToken.getPrincipal();
                Member member = memberMapper.findByUsername(username);
                if (member == null) {
                    throw new UnknownAccountException();
                }
                if (member.getStatus() == 0) {
                    throw new LockedAccountException();
                }
                /**
                 *
                 *
                 * Object principal, 从数据库中获取的用户对象
                 * Object hashedCredentials, 用户的密码
                 * ByteSource credentialsSalt, 加密盐  因为加密算法是公开
                 * String realmName 从前端传递登录用户名
                 */
                SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(member,member.getPassword(),null,username);
                return simpleAuthenticationInfo;
            }
        
      • b

报错解决

  1. The bean ‘securityManager’, defined in class path resource

2、加密

  • 1、配置类配置

    • ​ 注册

      /**
           * 基于数据数据用户表验证
           */
          @Bean
          public UserRealm realm(HashedCredentialsMatcher hashedCredentialsMatcher) {
              UserRealm userRealm = new UserRealm();
              // 注册到realm中
              userRealm.setCredentialsMatcher(hashedCredentialsMatcher);
              return userRealm;
          }
      
      
    • 配置加密算法

    注册  
    
    
    /**
         * 配置密码加密算法
         * @return
         */
        @Bean
        @Primary
        public HashedCredentialsMatcher hashedCredentialsMatcher(){
            //以md5进行加密
            HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(Md5Hash.ALGORITHM_NAME);
            //散列的次数,默认1次, 设置两次相当于 md5(md5(""));
            hashedCredentialsMatcher.setHashIterations(ShiroUtils.HASH_ITERATIONS);
            return hashedCredentialsMatcher;
        }
    }
    
    

    3、权限认证

  • 1、概论

    • 1.1、权限的分类

      • 数据权限 url
      • 资源权限 文件
      • 菜单权限
      • 元素权限
    • 1.2、权限mysql

      CREATE TABLE member_role_relation
      (
          id        int AUTO_INCREMENT PRIMARY KEY,
          role_id   int    NOT NULL COMMENT '角色主键',
          member_id bigint NOT NULL COMMENT '会员ID'
      );
      
      CREATE TABLE sys_role
      (
          role_id int AUTO_INCREMENT PRIMARY KEY COMMENT '主键',
          name    varchar(32) UNIQUE NOT NULL COMMENT '角色名',
          decl    varchar(255) COMMENT '角色说明',
          status  int DEFAULT 1 COMMENT '是否启用 1 启用 0 禁用'
      ) COMMENT '角色表';
      
      
      CREATE TABLE sys_permission
      (
          per_id int AUTO_INCREMENT PRIMARY KEY COMMENT '主键',
          name   varchar(128) UNIQUE NOT NULL COMMENT '权限名',
          decl   varchar(255) COMMENT '权限说明',
          status int DEFAULT 1 COMMENT '是否启用 1 启用 0 禁用'
      ) COMMENT '权限表';
      
      CREATE TABLE role_permission_relation
      (
          id      int AUTO_INCREMENT PRIMARY KEY COMMENT '主键',
          role_id int NOT NULL COMMENT '角色主键',
          per_id  int NOT NULL COMMENT '权限主键'
      ) COMMENT '角色与权限表';
      
  • 2、自定义类并继承AuthorizingRealm

     /**
             * 1 获取客服端传递过来的用户名
             */
            String username = (String) authenticationToken.getPrincipal();
            Member member = memberMapper.findByUsername(username);
            if (member == null) {
                throw new UnknownAccountException();
            }
            if (member.getStatus() == 0) {
                throw new LockedAccountException();
            }
            /**
             *
             *
             * Object principal, 从数据库中获取的用户对象
             * Object hashedCredentials, 用户的密码
             * ByteSource credentialsSalt, 加密盐  因为加密算法是公开
             * String realmName 从前端传递登录用户名
             */
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(member,member.getPassword(),null,username);
            return simpleAuthenticationInfo;
        }
        @Resource
        RolePermissionMapper rolePermissionMapper;
    
    //这句是授权的观念建
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            // 1 获取登录用户信息,该对象包含当前授权用户的名
            Member member = (Member) principalCollection.getPrimaryPrincipal();
    
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            // 2 通过用户ID获取所有的角色权限信息
            Long memberId = member.getMemberId();
            List<RoleVo> roleVos = rolePermissionMapper.selectRolesById(memberId);
    
    
            //3 转化数据 设置到simpleAuthorizationInfo中
            Set<String> roles = new HashSet<>();
            Set<String> permissions = new HashSet<>();
    
            //4、将对应的用户权限名称对应·赋值
            //如果验证成功,最终这里返回的信息authenticationInfo 的值与传入的第一个字段的值member相同
            roleVos.forEach(roleVo -> {
                roles.add(roleVo.getName());
                roleVo.getPermissions().forEach(permission -> {
                    permissions.add(permission.getName());
                });
            });
    
            simpleAuthorizationInfo.setRoles(roles);
            simpleAuthorizationInfo.setStringPermissions(permissions);
            return simpleAuthorizationInfo;
        }
    
  • 3、配置类配置

     @Bean
        public UserRealm realm(HashedCredentialsMatcher hashedCredentialsMatcher) {
            UserRealm userRealm = new UserRealm();
            // 注册到realm中
            userRealm.setCredentialsMatcher(hashedCredentialsMatcher);
            return userRealm;
        }
    /**
         * 配置密码加密算法
         * @return
         */
        @Bean
        @Primary
        public HashedCredentialsMatcher hashedCredentialsMatcher(){
            //以md5进行加密
            HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(Md5Hash.ALGORITHM_NAME);
            //散列的次数,默认1次, 设置两次相当于 md5(md5(""));
            hashedCredentialsMatcher.setHashIterations(ShiroUtils.HASH_ITERATIONS);
            return hashedCredentialsMatcher;
        }
    
    
  • 4、前端使用的注解

    注解功能说明
    @RequiresRoles(重点)已登录的用户需具有指定的角色才能访问
    @RequiresPermissions(重点)已登录的用户需具有指定的权限才能访问
    @RequiresGuest只有游客可以访问
    @RequiresAuthentication需要登录才能访问
    @RequiresUser已登录的用户或“记住我”的用户能访问

    @RequiresRoles(重点)

    @RestController
    @RequestMapping("/admin")
    public class AdminController {
    
        @GetMapping("/list")
        @RequiresRoles(value = {"admin", "dev"}, logical = Logical.OR)
        public String list() {
            return "查看列表信息";
        }
    
        @RequiresPermissions({"view"})
        @GetMapping("view")
        public String view() {
            return "查看列表信息";
        }
    
    
        @PostMapping("/add")
        @RequiresRoles("dev")
        @RequiresPermissions({"add"})
        public String save() {
            return "查看列表信息";
        }
    }
    
    

    4、JWT基于用户身份验证

说明:jwt token 令牌 校验 安全性的问题 令牌失效 续命jwt 10有效期 刷新令,jwt参考

  • 4.1、前端账号密码验证,向前端返回jssionId

    UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
            try {
                SecurityUtils.getSubject().login(usernamePasswordToken);
            } catch (UnknownAccountException | IncorrectCredentialsException uae) {
                throw new ControllerException(ResultCode.ACCOUNT_NOT_EXIST);
            } catch (LockedAccountException lae) {
                throw new ControllerException(ResultCode.SYSTEM_ERROR);
            }
            //获取会话中的id(相当于获取令牌)
            Serializable id = ShiroUtils.getSession().getId();
            //将令牌响应回前端
            return ResponseResult.success(id);
    
  • 4.2、校验jssionId(发起二次请求时),校验jssionId【继承DefaultWebSessionManager的自定类】

    从请求头中获取jssionId

    //主要定义了session的创建,启动,暂停与cookie的关联的定义
    public class CustomSessionManager extends DefaultWebSessionManager {
        //定义jwit
        private static final  String SHIRO_AUTH = "auth_token";
        private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
        public CustomSessionManager() {
            super();
        }
        @Override
        protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
            //获取前端来的请求,并获取令牌id
            String id = WebUtils.toHttp(request).getHeader(SHIRO_AUTH);
            //如果请求头中有 token 则其值为sessionId
            if (!StringUtils.isEmpty(id)) {
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
                return id;
            } else {
                //否则按默认规则从cookie取sessionId
                Serializable sessionId = super.getSessionId(request, response);
                return sessionId;
            }
        }
    
    }
    
  • 4.3、配置类的配置(注册与配置)

    /**
         * 基于数据数据用户表验证
         */
        @Bean
        public UserRealm realm(HashedCredentialsMatcher hashedCredentialsMatcher) {
            UserRealm userRealm = new UserRealm();
            // 注册到realm中
            userRealm.setCredentialsMatcher(hashedCredentialsMatcher);
            return userRealm;
        } 
     //配置请求session
     @Bean
        public CustomSessionManager webSessionManager(){
            CustomSessionManager customSessionManager = new CustomSessionManager();
            return customSessionManager;
        }
    

day(3-24)redis概论

1、redis概论

  • 1.1、应用场景
    • 缓冲

    • 验证码

2、redis安装

  • 1、window安装

  • 2、linux安装

    • docker-compose文件

      version: "3"
      services:
        redis-servier:
          image: redis:5
          environment:
            - TZ=Asia/Shanghai
          ports:
            - 6379:6379
          volumes:
            - ./redis/data:/data
      

3、redis文件配置

  • 1、redis配置文件配置

    spring:
      redis:
        host: 47.113.188.31
        port: 6739
        #指定数据库
        database: 0
        password: ""
        timeout: 3s
        #连接池配置
        jedis:
          pool:
            #最大连接数
            max-active: 10
            #连接池最大存活数
            max-idle: 8
            #连接池最小存活数
            min-idle: 2
    
    
  • 2、配置类的配置(键和值的分别序列化)

    @Bean
        public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
            return redisTemplate.opsForValue();
        }
    
        @Bean
        public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
            RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
            //配置序列化方式
            /*键的序列化,当键为String类型的时候*/
            StringRedisSerializer serializer = new StringRedisSerializer();
            redisTemplate.setKeySerializer(serializer);
            redisTemplate.setHashKeySerializer(serializer);
            /*值的序列化,当值为对象的时候*/
            Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
            redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);/*普通对象序列化*/
            redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);/*Map对象序列化*/
            //将自定的RedisTemplate注入到容器中
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            return redisTemplate;
        }
    

    user:uid:1:意思是user表,键值为1

4、redis基础使用

RedisTemplate:操作redsi

  • 验证码

    • valueOperations.set("hello", "world");
      //        valueOperations.set("phone:1xxxxx", 123456, Duration.ofMinutes(1));
      //        valueOperations.set("phone:1xxxxx1111", 123456, 1, TimeUnit.MINUTES);
      
  1. alueOperations.setIfAbsent(“hello”, “123”);如果键存在 则不设置 否则设置【分布式锁】

  2. valueOperations.setIfPresent(“hello”,234);如果键不存在 就不设置值 否则设置值

  3. valueOperations.getAndSet(“hello”, “修改”);获取旧值 设置新的值

  4. Duration.ofMinutes(1)设置数据的过期时间

  5. Long increment1 = valueOperations.increment(“distributed:user:id”, 2);自增 设置ID 可以用于分布式ID 【分布式id】,有自增因子

    • 分布式id

    • 自增 设置ID

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值