Shiro入门这篇就够了【Shiro的基础知识、回顾URL拦截】(三)

简介: 本文主要讲解的知识点有以下: 权限管理的基础知识 模型 粗粒度和细粒度的概念 回顾URL拦截的实现 Shiro的介绍与简单入门

cryptography:密码管理,提供了一套加密/解密的组件,方便开发。比如提供常用的散列、加/解密等功能。

  • 比如md5散列算法。


五、为什么使用Shiro


我们在使用URL拦截的时候,要将所有的URL都配置起来,繁琐、不易维护

而我们的Shiro实现系统的权限管理,有效提高开发效率,从而降低开发成本。

六、Shiro认证


6.1导入jar包


我们使用的是Maven的坐标就行了


<dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-quartz</artifactId>
            <version>1.2.3</version>
        </dependency>


当然了,我们也可以把Shiro相关的jar包全部导入进去

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-all</artifactId>
    <version>1.2.3</version>
</dependency>

6.2Shiro认证流程

26.jpg

这里写图片描述

6.2.1通过配置文件创建工厂

5.png

这里写图片描述


// 用户登陆和退出
    @Test
    public void testLoginAndLogout() {
        // 创建securityManager工厂,通过ini配置文件创建securityManager工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory(
                "classpath:shiro-first.ini");
        // 创建SecurityManager
        SecurityManager securityManager = factory.getInstance();
        // 将securityManager设置当前的运行环境中
        SecurityUtils.setSecurityManager(securityManager);
        // 从SecurityUtils里边创建一个subject
        Subject subject = SecurityUtils.getSubject();
        // 在认证提交前准备token(令牌)
        // 这里的账号和密码 将来是由用户输入进去
        UsernamePasswordToken token = new UsernamePasswordToken("zhangsan",
                "111111");
        try {
            // 执行认证提交
            subject.login(token);
        } catch (AuthenticationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // 是否认证通过
        boolean isAuthenticated = subject.isAuthenticated();
        System.out.println("是否认证通过:" + isAuthenticated);
        // 退出操作
        subject.logout();
        // 是否认证通过
        isAuthenticated = subject.isAuthenticated();
        System.out.println("是否认证通过:" + isAuthenticated);
    }

image.gif这里写图片描述


6.3小结

ModularRealmAuthenticator作用进行认证,需要调用realm查询用户信息(在数据库中存在用户信息)

ModularRealmAuthenticator进行密码对比(认证过程)。

realm:需要根据token中的身份信息去查询数据库(入门程序使用ini配置文件),如果查到用户返回认证信息,如果查询不到返回null


6.4自定义realm


从第一个认证程序我们可以看见,我们所说的流程,是认证器去找realm去查询我们相对应的数据。而默认的realm是直接去与配置文件来比对的,一般地,我们在开发中都是让realm去数据库中比对。

因此,我们需要自定义realm

6.jpg这里写图片描述


public class CustomRealm extends AuthorizingRealm {
    // 设置realm的名称
    @Override
    public void setName(String name) {
        super.setName("customRealm");
    }
    // 用于认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
        // token是用户输入的
        // 第一步从token中取出身份信息
        String userCode = (String) token.getPrincipal();
        // 第二步:根据用户输入的userCode从数据库查询
        // ....
        // 如果查询不到返回null
        //数据库中用户账号是zhangsansan
        /*if(!userCode.equals("zhangsansan")){//
            return null;
        }*/
        // 模拟从数据库查询到密码
        String password = "111112";
        // 如果查询到返回认证信息AuthenticationInfo
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                userCode, password, this.getName());
        return simpleAuthenticationInfo;
    }
    // 用于授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        // TODO Auto-generated method stub
        return null;
    }
}


6.5配置realm


需要在shiro-realm.ini配置realm注入到securityManager中。

7.png

image.gif这里写图片描述


6.6测试自定义realm


同上边的入门程序,需要更改ini配置文件路径:

同上边的入门程序,需要更改ini配置文件路径:
Factory<SecurityManager> factory = new IniSecurityManagerFactory(
                "classpath:shiro-realm.ini");


6.7散列算法


我们如果知道md5,我们就会知道md5是不可逆的,但是如果设置了一些安全性比较低的密码:111111…即时是不可逆的,但还是可以通过暴力算法来得到md5对应的明文…

建议对md5进行散列时加salt(盐),进行加密相当 于对原始密码+盐进行散列。\

正常使用时散列方法:

  • 在程序中对原始密码+盐进行散列,将散列值存储到数据库中,并且还要将盐也要存储在数据库中。

测试:


public class MD5Test {
    public static void main(String[] args) {
        //原始 密码 
        String source = "111111";
        //盐
        String salt = "qwerty";
        //散列次数
        int hashIterations = 2;
        //上边散列1次:f3694f162729b7d0254c6e40260bf15c
        //上边散列2次:36f2dfa24d0a9fa97276abbe13e596fc
        //构造方法中:
        //第一个参数:明文,原始密码 
        //第二个参数:盐,通过使用随机数
        //第三个参数:散列的次数,比如散列两次,相当 于md5(md5(''))
        Md5Hash md5Hash = new Md5Hash(source, salt, hashIterations);
        String password_md5 =  md5Hash.toString();
        System.out.println(password_md5);
        //第一个参数:散列算法 
        SimpleHash simpleHash = new SimpleHash("md5", source, salt, hashIterations);
        System.out.println(simpleHash.toString());
    }
}


6.8自定义realm支持md5


自定义realm


public class CustomRealmMd5 extends AuthorizingRealm {
    // 设置realm的名称
    @Override
    public void setName(String name) {
        super.setName("customRealmMd5");
    }
    // 用于认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
        // token是用户输入的
        // 第一步从token中取出身份信息
        String userCode = (String) token.getPrincipal();
        // 第二步:根据用户输入的userCode从数据库查询
        // ....
        // 如果查询不到返回null
        // 数据库中用户账号是zhangsansan
        /*
         * if(!userCode.equals("zhangsansan")){// return null; }
         */
        // 模拟从数据库查询到密码,散列值
        String password = "f3694f162729b7d0254c6e40260bf15c";
        // 从数据库获取salt
        String salt = "qwerty";
        //上边散列值和盐对应的明文:111111
        // 如果查询到返回认证信息AuthenticationInfo
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                userCode, password, ByteSource.Util.bytes(salt), this.getName());
        return simpleAuthenticationInfo;
    }
    // 用于授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        // TODO Auto-generated method stub
        return null;
    }
}


配置文件:

8.pngimage.gif这里写图片描述

测试:


// 自定义realm实现散列值匹配
    @Test
    public void testCustomRealmMd5() {
        // 创建securityManager工厂,通过ini配置文件创建securityManager工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory(
                "classpath:shiro-realm-md5.ini");
        // 创建SecurityManager
        SecurityManager securityManager = factory.getInstance();
        // 将securityManager设置当前的运行环境中
        SecurityUtils.setSecurityManager(securityManager);
        // 从SecurityUtils里边创建一个subject
        Subject subject = SecurityUtils.getSubject();
        // 在认证提交前准备token(令牌)
        // 这里的账号和密码 将来是由用户输入进去
        UsernamePasswordToken token = new UsernamePasswordToken("zhangsan",
                "222222");
        try {
            // 执行认证提交
            subject.login(token);
        } catch (AuthenticationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // 是否认证通过
        boolean isAuthenticated = subject.isAuthenticated();
        System.out.println("是否认证通过:" + isAuthenticated);
    }


七、总结


  • 用户认证和用户授权是Shiro的基础,用户认证其实上就是登陆操作、用户授权实际上就是对资源拦截的操作。
  • 权限管理的模型一般我们都将资源放在权限表中进行管理起来。
  • 我们可以基于角色拦截,也可以基于资源拦截。要是基于角色拦截的话,那么如果角色的权限发生变化了,那就需要修改代码了。推荐使用基于资源进行拦截
  • 这次URL拦截,我们使用一个JavaBean来封装所有的认证信息。当用户登陆了之后,我们就把用户对菜单栏的访问、对资源的访问权限都封装到该JavaBean中
  • 当使用拦截器进行用户认证的时候,我们只要判断Session域有没有JavaBen对象即可了。
  • 当时候拦截器进行用户授权的时候,我们要判断JavaBean中的权限是否能够访问该资源。
  • 以前URL拦截的方式需要把所有的URL都在数据库进行管理。非常麻烦,不易维护。
  • 我们希望Shiro去认证的时候是通过realm去数据库查询数据的。而我们reaml默认是查询配置文件的数据的。
  • 因此,我们需要自定义reaml,使得它是去数据库查询数据。只要继承AuthorizingRealm类就行了。
  • 当然了,自定义后的reaml也需要在配置文件中写上我们的自定义reaml的位置的。
  • 散列算法就是为了让密码不被别人给破解。我们可对原始的密码加盐再进行散列,这就加大了破解的难度了。
  • 自定义的reaml也是支持散列算法的,相同的,还是需要我们在配置文件中配置一下就好了。


目录
相关文章
|
11月前
|
安全 测试技术 网络安全
软件测试|测试平台开发-Flask 入门:URL组成部分详解
软件测试|测试平台开发-Flask 入门:URL组成部分详解
60 0
|
网络架构 Python
【flask入门系列】处理请求之url 路径参数的获取以及转换器的使用
这节我们写一下url路径参数的获取以及转换器的使用,学一下如何在我们的的url路径中加参数以及如何使用转换器,并且自定义转换器。
772 0
【flask入门系列】处理请求之url 路径参数的获取以及转换器的使用
|
1月前
|
安全 Java 数据安全/隐私保护
|
Java
Shiro学习-URL配置细节(六)
Shiro学习-URL配置细节(六)
65 0
|
JavaScript 网络协议 数据安全/隐私保护
Node.js入门之url模块和querystring模块
url模块和querystring模块是非常重要的两个URL处理模块。在做node服务端的开发时会经常用到。
150 0
|
Web App开发 JavaScript 安全
window.open(url)多次打开下载链接被浏览器拦截问题解决方案,js实现循环访问多个下载链接
window.open(url)多次打开下载链接被浏览器拦截问题解决方案,js实现循环访问多个下载链接
725 0
window.open(url)多次打开下载链接被浏览器拦截问题解决方案,js实现循环访问多个下载链接
|
Go 数据安全/隐私保护
Go 语言入门很简单:net/url 包(上)
在 Golang 中,将 URL 打包用于从服务器获取数据非常重要。只需了解您是否正在处理任何应用程序并且您想从任何外部位置或服务器获取此应用程序的数据,都需要我们可以使用 URL。
Go 语言入门很简单:net/url 包(下)
在 Golang 中,将 URL 打包用于从服务器获取数据非常重要。只需了解您是否正在处理任何应用程序并且您想从任何外部位置或服务器获取此应用程序的数据,都需要我们可以使用 URL。
|
存储 缓存 安全
Shiro入门这篇就够了【Shiro的基础知识、回顾URL拦截】(二)
本文主要讲解的知识点有以下: 权限管理的基础知识 模型 粗粒度和细粒度的概念 回顾URL拦截的实现 Shiro的介绍与简单入门
343 0
Shiro入门这篇就够了【Shiro的基础知识、回顾URL拦截】(二)