2

shiro安全框架从入门到精通实战!!!!

 1 month ago
source link: https://blog.51cto.com/teayear/10245918
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

shiro

1、String是不是基本的数据类型?

不是,是引用类型。 地址在 栈 中存放, 值:堆;
基本类型:整形,浮点型、布尔型、字符型。;栈

2、abstaract的mehtod能不能是static,同时是native, 同步的?

抽象类中可以有静态方法的。
抽象方法不能是静态的,需要被子类实现。静态方法无法被子类实现。
native:本地的。
不能???

3、String和StringBuffer、StringBuilder的区别?

String是不可变的的实例对象。
StringBuffer:线程安全
StringBuilder:线程不安全的

4、实现多态的机制?

1、继承关系(子类继承父类,子类实现接口)
2、父类引用 指向  子类对象;
3、子类要实现或者重写父类的方法

List list=new ArrayList();
List list=new LinkedList(); 

5、数组中有没有length方法,string中有没有length方法;

数组:length属性;
String中:length()方法;

1、shiro介绍

2、Springboot整合Shiro

1.shiro介绍

1.1介绍

  • shiro是一个java的 安全框架,apache的一个开源框架。简单易用。
  • 实现的功能:认证、授权、会话管理和密码加密等功能。
  • 可以用在java SE环境中,java EE环境中。

1.2shrio功能特点:

Authentication:认证

Authorization:授权

Session Management:session会话管理

Cryptography:密码加密

Caching:缓存

web Support:web支持

Concurrency:多线程、并发

Testing:测试

Run as: 以 某种 身份 运行

Remember Me:记住我

什么是认证:Authentication

通过用户名和密码,或者人脸识别,或者是指纹跟数据库里的数据进行匹配,如果匹配成功则代表认证通过;

什么是授权:Authorization

认证通过后,对不同的资源的访问进行控制,这就是授权的体现;

身份:用户名

凭证:密码

1.3shiro运行原理

Subject:主体,抽象的身份:当前的用户,网络爬虫、第三方的程序、进程

SecurityManager:安全管理器,管理所有的subjects;委托给SecurityManager进行安全管理。门面模式:Facade;需求----》委托人————分发下去;

Realm:域,数据域。获取数据库中用户信息、权限信息。

前台用户输入用户名和密码,点击登陆后,会使用一个subject进行login;

subject使用securitymanager.login方法进行登陆;

realm:数据域,它会处理login,会拿着前台输入的用户名和密码进行与数据库里的用户名和密码进行匹配,如果匹配成功,则认证通过;

//常用过滤器
/*
* anon:不需要认证就可以访问呢
*authc:必须认证才可以访问
* user:如果实现remenberme可以直接访问
* perms:必须授权才可以访问
* role:必须得到角色才可以访问
* */

2、shiro的认证步骤

2.1创建springboot项目

导入mybatis整合依赖;

导入MySQL驱动依赖;

导入druid依赖;

导入thymeleaf 依赖;

导入shiro和spring的整合依赖;

导入shiro和thymeleaf的整合依赖;

 <!--加入mybatis的依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <!--数据库连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.19</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>

        </dependency>
        <!--pagehelper的分页依赖-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.3</version>
        </dependency>
         <!--shiro标签和thymeleaf的整合依赖-->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>
         <!--spring和shiro的整合依赖-->
         <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.2.3</version>
        </dependency>
2.2配置文件

properties文件书写:


server.servlet.context-path=/demo


spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/shiro?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=123@qwe
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

spring.resources.static-locations=classpath:/resources/,classpath:/static/,classpath:/public/,classpath:/templates/


mybatis.type-aliases-package=com.aaa.demo_shiro.entity


pagehelper.helperDialect = mysql
pagehelper.reasonable = true
pagehelper.supportMethodsArguments = true
pagehelper.pageSizeZero =  true
pagehelper.params = countSql

logging.level.com.aaa.demo_shiro.mapper=debug

spring.thymeleaf.cache=false

spring.main.banner-mode=off
2.3从之前的项目中把班级管理拿过来

再把权限的五张表的数据拿过来;

在pom.xml文件中添加resources;

<!--配置扫描到java下面的xml文件 -->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>

            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
                <filtering>false</filtering>
            </resource>

        </resources>
2.4创建ShiroConfiguration类

该类是shiro的配置文件:

在该类中需要建立四个bean:

package com.example.demo_shiro.config;

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ShiroConfig {

    //realm  是自己定义的,用来实现前台的用户信息和数据库的用户信息进行匹配

    @Bean(name="userRealm")
    public UserRealm getUserRealm(){
        UserRealm userRealm = new UserRealm();
        return userRealm;
    }
    //安全管理器securitymanager
    @Bean(name="securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    //过滤器连工厂shirofilterfactorybean

    @Bean(name="shiroFilterFactoryBean")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        return shiroFilterFactoryBean;

    }
    //密码匹配器

    //shiro 与thymeleaf的整合
}


2.5创建测试页面、登陆、添加、修改页面

然后创建对应的controller方法

2.6修改和添加页面只有认证后才可以访问

在ShiroConfiguration中添加认证过滤

    @Bean(name="shiroFilterFactoryBean")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String,String> filtermap  = new LinkedHashMap<String,String>();
        filtermap.put("/test","anon");
        filtermap.put("/login","anon");
        filtermap.put("/**","authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filtermap);
        shiroFilterFactoryBean.setLoginUrl("toLogin");
        return shiroFilterFactoryBean;

    }
2.7修改认证逻辑

在controller方法的登陆方法中

三个步骤:
1.获取subject
2.封装token
3.登陆
@RequestMapping("login")
    public String login(String username,String password,Model model){
        System.out.println(username+"-->"+password);
        //第一步获取subject
        Subject subject = SecurityUtils.getSubject();
        //封装token
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        //第三步login方法
        try {
            subject.login(token);
            return "login";
        } catch (UnknownAccountException e) {
           model.addAttribute("msg","不存在该用户!");
            return "login";
        } catch (IncorrectCredentialsException e) {
            model.addAttribute("msg","密码凭证错误!");
            return "login";
        }catch (Exception e){
            model.addAttribute("msg","未知错误!");
            return "login";
        }

    }
2.8实现密码认证

自己定义一个密码加密器

public class UserCredentialsMatcher {
    /**
     * 随机生成 salt 需要指定 它的字符串的长度
     *
     * @param len 字符串的长度
     * @return salt
     */
    public static String generateSalt(int len) {
        //一个Byte占两个字节
        int byteLen = len >> 1;
        SecureRandomNumberGenerator secureRandom = new SecureRandomNumberGenerator();
        return secureRandom.nextBytes(byteLen).toHex();
    }

    /**
     * 获取加密后的密码,使用默认hash迭代的次数 1 次
     *
     * @param hashAlgorithm hash算法名称 MD2、MD5、SHA-1、SHA-256、SHA-384、SHA-512、etc。
     * @param password      需要加密的密码
     * @param salt          盐
     * @return 加密后的密码
     */
    public static String encryptPassword(String hashAlgorithm, String password, String salt) {
        return encryptPassword("MD5", password, salt, 2);
    }

    /**
     * 获取加密后的密码,需要指定 hash迭代的次数
     *
     * @param hashAlgorithm  hash算法名称 MD2、MD5、SHA-1、SHA-256、SHA-384、SHA-512、etc。
     * @param password       需要加密的密码
     * @param salt           盐
     * @param hashIterations hash迭代的次数
     * @return 加密后的密码
     */
    public static String encryptPassword(String hashAlgorithm, String password, String salt, int hashIterations) {
        SimpleHash hash = new SimpleHash(hashAlgorithm, password, salt, hashIterations);
        return hash.toString();
    }

}

在ShiroConfig中定义凭证匹配器

//密码匹配器
    @Bean(name="hashedCredentialsMatcher")
    public HashedCredentialsMatcher getHashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        hashedCredentialsMatcher.setHashIterations(2);
        return hashedCredentialsMatcher;
    }

给realm设置匹配器

@Bean(name="userRealm")
    public UserRealm getUserRealm(@Qualifier("hashedCredentialsMatcher")HashedCredentialsMatcher hashedCredentialsMatcher){
        UserRealm userRealm = new UserRealm();
        userRealm.setCredentialsMatcher(hashedCredentialsMatcher);
        return userRealm;
    }

在realm中设置如下:

SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(), ByteSource.Util.bytes(user.getSalt()),getName());

3.shiro的授权步骤

3.1 测试授权
@Bean(name="shiroFilterFactoryBean")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String,String> filtermap  = new LinkedHashMap<String,String>();
        filtermap.put("/test","anon");
        filtermap.put("/login","anon");
        filtermap.put("/user/add","perms[user:add]");
        filtermap.put("/user/update","perms[user:update]");
        filtermap.put("/classes/findall","perms[classes:findall]");

        filtermap.put("/**","authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filtermap);
        shiroFilterFactoryBean.setLoginUrl("/toLogin");
        shiroFilterFactoryBean.setSuccessUrl("/hello");
        shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");
        return shiroFilterFactoryBean;

    }
3.2授权
 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行授权方法");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //获取当前认证过的用户
        Subject subject = SecurityUtils.getSubject();
        SysUser user = (SysUser) subject.getPrincipal();
        //查询该用户所有的授权
        List<SysPermission> ps = null;
        try {
             ps = sysService.findPermissionListByUserId(user.getId());
        } catch (Exception e) {
            e.printStackTrace();
        }
        Set<String> permissions = new HashSet<String>();
        for(SysPermission p:ps){
            permissions.add(p.getPercode());
        }
        info.setStringPermissions(permissions);
        return info;
    }
3.3不同的授权看到不同的资源
 <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

在配置类中添加bean

//配置shiroDialect,用于thymeleaf和shiro的合用
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }

在test前端写代码

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <meta charset="UTF-8">
    <title>测试界面</title>
</head>
<body>

    <shiro:hasPermission name="classes:findall">
        班级管理:<a rel="nofollow" href="classes/findall">班级管理</a><br>
    </shiro:hasPermission>

<shiro:hasPermission name="user:add">
    用户添加:<a rel="nofollow" href="user/add">添加用户</a><br>
    </shiro:hasPermission>
<shiro:hasPermission name="user:update">
用户修改:<a rel="nofollow" href="user/update">修改用户</a><br>
</shiro:hasPermission>
</body>
</html>

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK