Shiro安全框架简单介绍

本文详细介绍Apache Shiro安全框架,包括其与Spring Security的对比、整体架构、环境准备及认证、授权步骤。通过实例代码讲解如何使用Shiro进行认证、授权、加密加盐等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Shiro安全框架的简单概括

简介

1.Apache的强大灵活的开源安全框架;
2.Shiro可以完成认证、授权、企业会话管理、缓存管理、安全加密、web集成等功能;

Shiro与Spring Security比较

Apache ShiroSpring Secuti
简单、灵活、可脱离Spirng、粒度较粗复杂、笨重、不可脱离Spring、粒度较细

Shiro的整体架构

在这里插入图片描述
注意:Shiro不会维护用户和维护权限;这些需要自己去设计/提供,然后通过相应的接口注入给Shiro即可。

环境的准备

创建一个基于Maven的项目,且准备好以下依赖

<dependencies>
    <dependency>
        <!--引入shiro的核心包-->
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.4.0</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
</dependencies>

Shiro认证步骤

1、创建SecurityManager
2、主体提交认证
3、SecurityManager认证
4、Authentication认证
5、Relam验证

Shiro认证代码如下

package com.haibin.test;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test;

public class AuthenticationTest {
   
    SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();

    @Before
    public void addUser() {
        simpleAccountRealm.addAccount("Mark", "123456");
    }

    @Test
    public void testAuthentication() {
        //1、构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(simpleAccountRealm);
        //2、主体提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("Mark", "123456");
        subject.login(token);

        System.out.println("isAuthentication:" + subject.isAuthenticated());

        subject.logout();
        System.out.println("isAuthentication:" + subject.isAuthenticated());
    }
}

注意:Realm:域,Shiro 从 Realm 获取安全数据(如用户、角色、权限),就是说 SecurityManager 要验证用户身份,那么它需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色 / 权限进行验证用户是否能进行操作;可以把 Realm 看成 DataSource,即安全数据源。

Shiro授权步骤

1、创建SecurityManager
2、主体授权
3、SecurityManager授权
4、Authenrizer授权
5、Realm获取角色权限数据

Shiro授权代码如下

//代码大部分与认证的相同,只在以下两处做了修改
simpleAccountRealm.addAccount("Mark", "123456","admin","user");
//检查用户是否具备这个权限
subject.checkRoles("admin","user");

IniRealm的使用

//创建iniRealm对象,且读取这个文件
        IniRealm iniRealm = new IniRealm("classpath:user.ini");
        //1、构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //将iniRealm设置到SecurityManager环境中
        defaultSecurityManager.setRealm(iniRealm);
        //2、主体提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("Mark", "123456");

        subject.login(token);

        System.out.println("isAuthentication:" + subject.isAuthenticated());
        subject.checkRole("admin");
        subject.checkPermissions("user:delete","user:update");

user.ini文件

[users]
Mark=123456,admin
[roles]
admin=user:delete,user:update

JdbcRealm的使用

1、访问数据库,就要在pom.xml中添加数据库驱动,数据源的依赖

		<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>

2、用户表
在这里插入图片描述
3、角色表
在这里插入图片描述
4、主要代码

//设置一个数据源,所以先创建一个数据源对象
    DruidDataSource dataSource = new DruidDataSource();
    //要访问数据库,首先要想到访问数据库的三要素url,username,password

    {
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
    }

    @Test
    public void testAuthentication() {
        //创建jdbcRealm
        JdbcRealm jdbcRealm = new JdbcRealm();
        //jdbcRealm设置一个数据源
        jdbcRealm.setDataSource(dataSource);
        //设置为ture才不会查询权限数据
        jdbcRealm.setPermissionsLookupEnabled(true);

        //自定义用户表sql语句
        String sql = "select password from test_user where username=?";
        jdbcRealm.setAuthenticationQuery(sql);

        //自定义角色表语句
        String roleSql = "select role_name from test_user_role where username=?";
        jdbcRealm.setUserRolesQuery(roleSql);

        //1、构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //将jdbcRealm设置到SecurityManager环境中
        defaultSecurityManager.setRealm(jdbcRealm);

        //2、主体提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("xiaoming", "654321");

        subject.login(token);

        System.out.println("isAuthentication:" + subject.isAuthenticated());
        /*
        subject.checkRole("admin");
        subject.checkRoles("admin","user");
        subject.checkPermission("user:select");
        */
        subject.checkRole("user");
    }

自定义Realm

代码如下:

public class CustomRealm extends AuthorizingRealm {

    Map<String, String> userMap = new HashMap<String, String>(16);

    {
        userMap.put("Mark", "123456");
        super.setName("CustomRealm");
    }

        //授权的抽象方法
        //参数是主体传过来的授权信息
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String userName= (String) principalCollection.getPrimaryPrincipal();
        //从数据库或者缓存中获取角色数据
        Set<String> roles=getRolesByUserName(userName);
        //从数据或者缓存中获取权限数据
        Set<String> permissions=getPermissionByUserName(userName);

        SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setStringPermissions(permissions);
        simpleAuthorizationInfo.setRoles(roles);
        return simpleAuthorizationInfo;
    }

    private Set<String> getPermissionByUserName(String userName) {
        Set<String> sets=new HashSet<String>();
        sets.add("user:add");
        sets.add("user:delete");
        return sets;
    }

    private Set<String> getRolesByUserName(String userName) {
        Set<String> sets=new HashSet<String>();
        sets.add("admin");
        sets.add("user");
        return sets;
    }





    //认证的抽象方法
    //参数是主体传过来的认证信息
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
            throws AuthenticationException {
        //1、从主体传过来的认证信息中获取用户名
        String userName = (String) authenticationToken.getPrincipal();
        //2、通过用户名到数据库中获取凭证
        String password = getPasswordByUserName(userName);
        if (password == null) {
            return null;
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo
                ("Mark", "123456", "CustomRealm");
        return authenticationInfo;
    }

    /*
    省略时间,这里没有创建数据库,前面创建一个集合且赋值,模拟数据库
     */
    private String getPasswordByUserName(String userName) {
        return userMap.get(userName);
    }

测试类代码:

public class CustomRealmTest {
    @Test
    public void testAuthentication() {
        //创建customRealm对象
        CustomRealm customRealm=new CustomRealm();

        //1、构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //将customRealm加入到这个环境中
        defaultSecurityManager.setRealm(customRealm);

        //2、主体提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("Mark", "123456");

        subject.login(token);

        System.out.println("isAuthentication:" + subject.isAuthenticated());

        /*
        subject.checkRole("admin");
        subject.checkPermissions("user:delete","user:update");
        */
        subject.checkRole("admin");
        subject.checkPermissions("user:add","user:delete");
    }

Shiro的加密加盐

代码在自定义的realmd的基础上做以下修改

public static void main(String[] args){
        String md5Hash=new Md5Hash("123456","Mark").toHex();
        System.out.println(md5Hash.toString());
    }

运行main()方法得到加密后密码的字符串复制到userMap中

Map<String, String> userMap = new HashMap<String, String>(16);

    {
        userMap.put("Mark","283538989cef48f3d7d8a1c1bdf2008f    ");
        super.setName("CustomRealm");
    }

加盐后需要在认证的抽象方法中添加的代码

SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo
                ("Mark", "123456", "CustomRealm");
        //加盐后需要添加的代码
        authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("Mark"));
        return authenticationInfo;

然后在测试类SecurityManager环境后添加一下代码即可

//加密
        //创建一个matcher对象
        HashedCredentialsMatcher matcher=new HashedCredentialsMatcher();

        //设置加密的名称
        matcher.setHashAlgorithmName("md5");

        //设置加密的次数
        matcher.setHashIterations(1);

        //把matcher对象设置金自定义realm中
        customRealm.setCredentialsMatcher(matcher);

##总结的有点粗糙,还请多多包容,刚开始写这类文章。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值