shiro学习(通俗易懂)

目录

一、什么是shiro?

shiro是apache旗下的一个开源框架,它将软件系统的安全认证的功能抽取出来,简单易用,实现用户身份认证,权限授权,加密、会话、管理等功能,组成了一个通用的安全认证框架。

详细了解shiro链接如下:
https://shiro.apache.org/architecture.html
如下图,红色框住的就是shiro最核心部分,图大家简单有个印象即可
在这里插入图片描述
若文章有错误地方,欢迎评论交流

二、第一个shiro用户认证程序

认证:我们现在应该知道了,身份认证,就是判断一个用户是否为合法用户的过程,也就是最常用的简单身份认证方式,比如登录时对用户输入的账号密码进行验证,判断是否与系统中存储的用户名和密码一致。

注:我IDEA写的代码会压缩成压缩包放在最后以百度网盘链接给出,供大家参考

shiro中对于不同对象有自己的称呼
1、Subject:主体
如登录的用户
2、Principal:身份信息
如用户的用户名,手机号,邮箱这种具有唯一标识的身份信息,主身份(Primary Principal)作为登录的信息,因为不可能所有身份都作为登录的,那多且太麻烦了,只要账号这种身份信息作为登录即可。
3、Credential:凭证信息
主体对象自己知道的安全信息,如密码。注意下面图,等下认证程序就是跟着这幅图写
在这里插入图片描述

构建一个Maven项目,直接构建一个quickstart的即可
在这里插入图片描述

建好项目就导入依赖

<dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.5.3</version>
</dependency>

接下来新建resources文件夹,放入shiro的配置文件,叫shiro.ini,这个配置文件只在刚学习的时候用,后面整合SpringBoot不用这个,这里相当于伪造数据。

[users]
xiaoming=123
zhangsan=123456
yx5411=12345

接着建立一个认证类TestAuthenticator,目录结构如下
在这里插入图片描述

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;

public class TestAuthenticator {
    //根据认证流程写
    public static void main(String[] args) {
        //1、创建安全管理器对象
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        //2、给安全管理器设置realm,new IniRealm()是读取shiro.ini
        securityManager.setRealm(new IniRealm("classpath:shiro.ini"));
        //3、给全局安全工具类SecurityUtils设置安全管理器
        SecurityUtils.setSecurityManager(securityManager);
        //4、关键对象subject主体
        Subject subject = SecurityUtils.getSubject();
        //5、创建令牌
        UsernamePasswordToken token = new UsernamePasswordToken("xiaoming","123");
        try{
            System.out.println("认证状态:"+subject.isAuthenticated());
            subject.login(token);//用户认证(登录)
            System.out.println("认证状态:"+subject.isAuthenticated());
        }catch (Exception e){
            e.printStackTrace();//认证不通过会报异常
        }
    }
}

在这里插入图片描述
若将令牌的账号变成xiaobai,没有这个账号,则会报未知账户异常
在这里插入图片描述
在这里插入图片描述
如果是密码不对,就会报凭证不正确异常,也就是密码错误
在这里插入图片描述
在这里插入图片描述
于是可以专门捕获这两个异常,用于提示用户
在这里插入图片描述

三、自定义Realm实现

上面是用配置文件自己伪造了数据,如果我们要连接上数据库呢?这里就需要自定义Realm了,Realm就是和数据库连接的。
在这里插入图片描述
上面代码就是运行TestCustomerRealmAuthenticator类,假设登录输入账号密码是xiaoming,1234,由SimpleAuthenticationInfo查到数据库中对应用户名的密码是123,密码不同,就会返回凭证不正确异常(即密码错误),注意这里都是自己弄的假数据,真正连接数据库要用jdbc和mybatis。我们后面都先用CustomerRealm这种造伪数据,也就是假设从数据库中查出的,等真正整合SpringBoot再连接真正数据库。
在这里插入图片描述

如果改成下图,数据库中没有输入的用户,就会显示用户名错误
在这里插入图片描述
在这里插入图片描述

CustomerRealm.java

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

/**
 * 自定义realm实现,将认证/授权数据的来源转为数据库的实现
 */
public class CustomerRealm extends AuthorizingRealm {
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //token中获取用户名
        String principal = (String) authenticationToken.getPrincipal();//用户名(输入的)
        //根据这个身份信息,用jdbc或者mybatis和数据库中数据比对,看有没有这个用户
        //下面我们就不查了,做一个伪数据,假设数据库中只有小明这一个用户数据,后续和SpringBoot整合再连接数据库,假设xiaoming是数据库中仅存的数据
        if ("xiaoming".equals(principal)){
            //三个参数表示从数据库中查到的账号和密码,最后一个就是Realm的名字,直接用getName即可
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal,"123",this.getName());
            return simpleAuthenticationInfo;
        }
        return null;
    }
}

TestCustomerRealmAuthenticator.java

import com.yx.realm.CustomerRealm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;

/**
 * 使用自定义的realm
 */
public class TestCustomerRealmAuthenticator {
    public static void main(String[] args) {
        //1、创建SecurityManager
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //2、设置自定义realm
        defaultSecurityManager.setRealm(new CustomerRealm());
        //3、给全局安全工具类SecurityUtils设置安全管理器
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //4、关键对象subject主体
        Subject subject = SecurityUtils.getSubject();
        //5、创建令牌
        UsernamePasswordToken token = new UsernamePasswordToken("xiaoming","1234");
        try{
            subject.login(token);
        }catch (UnknownAccountException e){
            e.printStackTrace();
            System.out.println("用户名错误");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();//认证不通过会报异常
            System.out.println("密码错误");
        }
    }
}

四、MD5算法加密

我们这里是没有进行加密的,伪造查到的数据库中数据123也是明文,不安全,尤其是以后用户支付密码,那就更不能明文存储了
在这里插入图片描述
我们会用MD5+Salt进行加密,MD5是不可逆的,只能明文生成密文,同一个明文每次生成的密文都是一致的,有些网站所谓的MD5破解,只是将一些常见的密码,比如123456,root,888888,这种简单密码,做了一个密文数据库,如果有匹配,那就给你返回它存储的明文,但稍微难一点的都不能。所以我们在设置密码的时候,都会提示你要数字+英文字符这样这种网站就推不出来了。但是虽然网站这样提示要求,最后用户也可能输入一个aaa123456这种简单又符合输入要求的,所以就需要加密算法再提升一下,也就是用Salt,让加密更加复杂化,会在MD5加密后的字符串后面再加几个随机复杂字符。

测试一下Md5加密

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

public class TestShiroMd5 {
    public static void main(String[] args) {
        Md5Hash md5Hash = new Md5Hash("123");//给123加密
        System.out.println(md5Hash.toHex());

        //Md5+salt处理
        Md5Hash md5Hash1 = new Md5Hash("123","x0*7p");//这个盐这里定死了,后面一个写一个随机生成字符的方法
        System.out.println(md5Hash1.toHex());

        //Md5+salt处理+hash散列
        Md5Hash md5Hash2 = new Md5Hash("123","x0*7p",1024);//1024表示散列1024次,更加复杂与安全
        System.out.println(md5Hash2.toHex());
    }
}

加密后就是16进制的32位字符串,最后一个最复杂,也最安全
在这里插入图片描述

在这里插入图片描述
两个类
TestCustomerMD5RealmAuthenticator .java

import com.yx.realm.CustomerMd5Realm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;

public class TestCustomerMD5RealmAuthenticator {
    public static void main(String[] args) {
        //1、创建SecurityManager
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //2、设置自定义realm
        CustomerMd5Realm realm = new CustomerMd5Realm();
        //设置realm使用hash凭证匹配器,用md5
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        realm.setCredentialsMatcher(hashedCredentialsMatcher);
        defaultSecurityManager.setRealm(realm);
        //3、给全局安全工具类SecurityUtils设置安全管理器
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //4、关键对象subject主体
        Subject subject = SecurityUtils.getSubject();
        //5、创建令牌
        UsernamePasswordToken token = new UsernamePasswordToken("xiaoming","123");
        try{
            subject.login(token);
            System.out.println("登录成功");
        }catch (UnknownAccountException e){
            e.printStackTrace();
            System.out.println("用户名错误");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();//认证不通过会报异常
            System.out.println("密码错误");
        }
    }
}

CustomerMd5Realm.java

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

//Md5+salt+hash
public class CustomerMd5Realm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String principal = (String) authenticationToken.getPrincipal();//用户名(输入的)
        if ("xiaoming".equals(principal)){
            //三个参数表示从数据库中查到的账号和密码,最后一个就是Realm的名字,直接用getName即可
            return new SimpleAuthenticationInfo(principal,"202cb962ac59075b964b07152d234b70",this.getName());
        }
        return null;
    }
}

用MD5加密需要在设置自定义realm改一改,加一个设置md5,因为默认不是md5,相当于告诉程序用md5加密,运行TestCustomerMD5RealmAuthenticator 类
在这里插入图片描述
CustomerMd5Realm.java加入salt
在这里插入图片描述
同样运行TestCustomerMD5RealmAuthenticator 类
在这里插入图片描述
这里他会自动加上盐,再与数据库中这个加密的字符串比较

再加上Hash散列呢,散列可是散列1024次
在这里插入图片描述
TestCustomerMD5RealmAuthenticator 类中加上散列多少次,相当于告诉密码散列了多少次
在这里插入图片描述
在这里插入图片描述
以上就是MD5+Salt+Hash散列加密方式,我们再把核心代码贴出来

public class TestCustomerMD5RealmAuthenticator {
    public static void main(String[] args) {
        //1、创建SecurityManager
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //2、设置自定义realm
        CustomerMd5Realm realm = new CustomerMd5Realm();
        //设置realm使用hash凭证匹配器,用md5
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        hashedCredentialsMatcher.setHashIterations(1024);
        realm.setCredentialsMatcher(hashedCredentialsMatcher);
        defaultSecurityManager.setRealm(realm);
        //3、给全局安全工具类SecurityUtils设置安全管理器
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //4、关键对象subject主体
        Subject subject = SecurityUtils.getSubject();
        //5、创建令牌
        UsernamePasswordToken token = new UsernamePasswordToken("xiaoming","123");
        try{
            subject.login(token);
            System.out.println("登录成功");
        }catch (UnknownAccountException e){
            e.printStackTrace();
            System.out.println("用户名错误");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();//认证不通过会报异常
            System.out.println("密码错误");
        }
    }
}



//MD5+Salt+Hash
public class CustomerMd5Realm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String principal = (String) authenticationToken.getPrincipal();//用户名(输入的)
        if ("xiaoming".equals(principal)){
            //三个参数表示从数据库中查到的账号和密码,最后一个就是Realm的名字,直接用getName即可
            return new SimpleAuthenticationInfo(principal,
                    "4d41fdb34ea9f4b5dd2b890a3b89943e",
                    ByteSource.Util.bytes("x0*7p"),
                    this.getName());
        }
        return null;
    }
}

五、shiro中的授权

之前是认证,也就是登录进行认证,现在是授权,也就是访问权限,不同用户具有不同的访问权限,如对某些用户密码修改权限,只能管理员才能有。授权是基于认证的,因为你只有合法登录通过,你才有一些访问权限。
在这里插入图片描述

两种授权方式:1、基于角色的访问控制 2、基于资源的访问控制

我们直接来实践一下,再来讲解,我们接着用md5+salt
+hash的认证后面加内容,因为授权要先认证通过,也就是要先登录通过。

CustomerMd5Realm.java

首先基于角色的访问控制,假设xiaoming有两个角色,admin和user,后面SpringBoot整合真正写数据库,现在先造这两个数据,一般用户有哪些角色都会存在数据库中。

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

//Md5+salt+hash
public class CustomerMd5Realm extends AuthorizingRealm {
	//授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();//用户名
        System.out.println("身份信息:"+primaryPrincipal);
        //将数据库查询的角色信息赋值给权限对象,这里先用伪数据
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addRole("admin");//管理员角色
        simpleAuthorizationInfo.addRole("user");//用户角色
        return simpleAuthorizationInfo;
    }
	//认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String principal = (String) authenticationToken.getPrincipal();//用户名(输入的)
        if ("xiaoming".equals(principal)){
            //三个参数表示从数据库中查到的账号和密码,最后一个就是Realm的名字,直接用getName即可
            return new SimpleAuthenticationInfo(principal,
                    "4d41fdb34ea9f4b5dd2b890a3b89943e",
                    ByteSource.Util.bytes("x0*7p"),
                    this.getName());
        }
        return null;
    }
}

TestCustomerMD5RealmAuthenticator.java

import com.yx.realm.CustomerMd5Realm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;

import java.util.Arrays;

public class TestCustomerMD5RealmAuthenticator {
    public static void main(String[] args) {
        //认证

        //1、创建SecurityManager
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //2、设置自定义realm
        CustomerMd5Realm realm = new CustomerMd5Realm();
        //设置realm使用hash凭证匹配器,用md5
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        hashedCredentialsMatcher.setHashIterations(1024);
        realm.setCredentialsMatcher(hashedCredentialsMatcher);
        defaultSecurityManager.setRealm(realm);
        //3、给全局安全工具类SecurityUtils设置安全管理器
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //4、关键对象subject主体
        Subject subject = SecurityUtils.getSubject();
        //5、创建令牌
        UsernamePasswordToken token = new UsernamePasswordToken("xiaoming","123");
        try{
            subject.login(token);
            System.out.println("登录成功");
        }catch (UnknownAccountException e){
            e.printStackTrace();
            System.out.println("用户名错误");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();//认证不通过会报异常
            System.out.println("密码错误");
        }

        //授权
        if(subject.isAuthenticated()){
            //基于角色权限控制
            System.out.println(subject.hasRole("admin"));
            System.out.println("--------------------");
            //基于多角色权限控制(要都有,一个没有都不行)
            System.out.println(subject.hasAllRoles(Arrays.asList("admin", "user")));
            System.out.println(subject.hasAllRoles(Arrays.asList("super","user")));
            System.out.println("--------------------");
            //基于多角色权限控制(只要有其中一个)
            boolean[] booleans = subject.hasRoles(Arrays.asList("admin", "user", "super"));
            for (boolean b : booleans) {
                System.out.println(b);
            }
        }
    }
}

如下基于角色的结果,可以用hasRole、hasAllRoles、hasRoles
在这里插入图片描述

再来讲基于权限的访问控制
资源标识符:操作:资源类型,操作就是创建+增删改查,举个例子,xiaoming依然有两个角色,admin和user。数据库中查询到的也有两个权限,user:*:yx5411product:create:*,意思分别是user对yx5411这个用户数据有所有操作权限,product对所有商品都有创建权限

CustomerMd5Realm.java授权部分代码,这里用于造数据,后面整合SpringBoot再连接真正数据库,先用伪数据

@Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();//用户名
        System.out.println("身份信息:"+primaryPrincipal);
        //将数据库查询的角色信息赋值给权限对象,这里先用伪数据
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addRole("admin");//管理员角色
        simpleAuthorizationInfo.addRole("user");//用户角色

        //将数据库查询的权限信息赋值给权限对象,这里先用伪数据,表示用户对yx5411有操作权限,即增删改查的权限
        simpleAuthorizationInfo.addStringPermission("user:*:yx5411");
        simpleAuthorizationInfo.addStringPermission("product:create:*");
        return simpleAuthorizationInfo;
    }

TestCustomerMD5RealmAuthenticator.java授权部分代码

//授权
        if(subject.isAuthenticated()){
            //基于角色权限控制
            System.out.println(subject.hasRole("admin"));
            System.out.println("--------------------");
            //基于多角色权限控制(要都有,一个没有都不行)
            System.out.println(subject.hasAllRoles(Arrays.asList("admin", "user")));
            System.out.println(subject.hasAllRoles(Arrays.asList("super","user")));
            System.out.println("--------------------");
            //基于多角色权限控制(只要有其中一个)
            boolean[] booleans = subject.hasRoles(Arrays.asList("admin", "user", "super"));
            for (boolean b : booleans) {
                System.out.println(b);
            }
            System.out.println("--------------------");

            //基于权限的访问控制,资源标识符:操作:资源类型,操作就是创建+增删改查
            System.out.println("权限:"+subject.isPermitted("user:*:*"));//xiaoming对所有用户都有操作权限吗?false
            System.out.println("权限:"+subject.isPermitted("user:*:yx"));//xiaoming对yx用户都有操作权限吗?false
            System.out.println("权限:"+subject.isPermitted("user:*:yx5411"));//xiaoming对yx5411用户都有操作权限吗?true

            System.out.println("-----------------------");
            System.out.println("权限:"+subject.isPermitted("product:update:*"));//product:update:*也可以写成product:update
            System.out.println("权限:"+subject.isPermitted("product:create"));

            System.out.println("----------------");
            //分别具有哪些权限
            boolean[] booleans1 = subject.isPermitted("user:*:aaa", "user:*:yx5411","product:update");
            for (boolean b : booleans1) {
                System.out.println(b);
            }
            System.out.println("------------------");
            //同时具有哪些权限
            System.out.println(subject.isPermittedAll("user:*:yx5411", "product:create:*"));
        }

在这里插入图片描述

六、shiro整合SpringBoot

之前用的数据都是在Realm自己造的,现在我们真正整合SpringBoot创建数据库。shiro会将所有页面请求都拦截,然后进行安全判断,通过才放行,这个通过也分认证通过和授权通过。

6.1 环境搭建

我们先用Jsp+SpringBoot进行演示,不用纠结于Jsp过时问题,jsp页面只是一个静态资源,换成html也一样,也不搞啥前后端分离了,这只是为了整合起来学习shiro,后面还会写Thymeleaf+SpringBoot版本。

首先IDEA创建一个SpringBoot项目,不过多赘述,大家这个肯定没问题
在这里插入图片描述

main下新建webapp然后创建一个index.jsp,这三部分下面贴上代码
index.jsp

<%@ page contentType="text/html; charset=utf-8" pageEncoding="UTF-8" isELIgnored="false" %>
<!doctype html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title></title>
        <meta name="keywords" content="">
        <meta name="description" content="">
    </head>
    <body>
       	<h1>系统主页</h1>
        <ul>
            <li><a href="">用户管理</a></li>
            <li><a href="">商品管理</a></li>
            <li><a href="">订单管理</a></li>
            <li><a href="">物流管理</a></li>
        </ul>
    </body>
</html>

login.jsp

<%@ page contentType="text/html; charset=utf-8" pageEncoding="UTF-8" isELIgnored="false" %>
<!doctype html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title></title>
    <meta name="keywords" content="">
    <meta name="description" content="">
</head>
<body>
    <h1>用户登录界面</h1>
</body>
</html>

application.properties

server.port=8080
server.servlet.context-path=/shiro
spring.application.name=shiro

spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.yx</groupId>
    <artifactId>shiro-springboot-jsp</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>shiro-springboot-jsp</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--jsp解析依赖-->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.yml</include>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>

</project>

在这里插入图片描述
配置一下工作目录,jsp需要弄下这个
在这里插入图片描述
运行ShiroSpringbootJspApplication,输入地址,SpringBoot环境搭建成功
在这里插入图片描述
在这里插入图片描述

接下来整合shiro
在这里插入图片描述
首先引入依赖

<!--Shiro-SpringBoot依赖-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.5.3</version>
        </dependency>

然后进行shiro配置
ShiroConfig.java

import com.yx.shiro.realms.CustomerRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {
    //1、创建shiroFilter(用于拦截所有请求)
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //给filter设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        //配置系统的受限资源和公共资源
        Map<String,String> map = new HashMap<>();
        map.put("/index.jsp","authc");//index.jsp要求认证,没有认证就会默认跳转到/login.jsp页面,这个也可以设置,用shiroFilterFactoryBean.setLoginUrl("跳转地址");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }
    //2、创建web安全管理器
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(getRealm());
        return defaultWebSecurityManager;
    }
    //3、创建自定义realm
    @Bean
    public Realm getRealm(){
        CustomerRealm customerRealm = new CustomerRealm();
        return customerRealm;
    }
}

在这里插入图片描述
常用anon和authc,也就是所有人都可访问和必须认证登录后才能访问

CustomerRealm.java,现在还没有做操作,只是有基本框架

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

//自定义Realm
public class CustomerRealm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        return null;
    }
}

重新运行,然后输入地址 http://localhost:8080/shiro/index.jsp,发现会自动跳转到login.jsp页面,这是由于设置了index.jsp页面需要认证,没有认证默认会跳转到login.jsp,这个默认跳转的界面可以自己设置,不设置默认是login.jsp

接下来我们做一个真正的登录页面,如下,将body替换一下即可
在这里插入图片描述
login.jsp

<body>
    <h1>用户登录界面</h1>

    <form action="${pageContext.request.contextPath}/user/login" method="post">
        <tr>
            <td>用户:</td>
            <td><input type="text" name="username"></td>
        </tr>
        <tr>
            <td>密码</td>
            <td><input type="text" name="password"></td>
        </tr>
        <input type="submit" value="登录">
    </form>
</body>

ShiroConfig也需要改变一点,主要就是map.put,拦截所有/**,只让/user/login是公共资源,可以放行,不拦截

//1、创建shiroFilter(用于拦截所有请求)
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //给filter设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        //配置系统的受限资源和公共资源
        Map<String,String> map = new HashMap<>();
        map.put("/user/login","anon");//login为公共资源,不要认证,不写这个将login也拦截,那么就会一直在login.jsp界面跳转
        map.put("/**","authc");//拦截所有,所有都要认证
        //map.put("/index.jsp","authc");//index.jsp要求认证,没有认证就会默认跳转到/login.jsp页面,这个也可以设置,用shiroFilterFactoryBean.setLoginUrl("跳转地址");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

UserController.java负责用户登录的业务逻辑,登录就是获取subject主体对象,也就是登录的对象,然后subject.login()进行登录认证

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("user")
public class UserController {

    @RequestMapping("loginout")
    public String loginout(){
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "redirect:/login.jsp";
    }

    /**
     * 身份认证
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("login")
    public String login(String username,String password){
        //用shiro来做安全认证
        //获取主题对象
        Subject subject = SecurityUtils.getSubject();//会自动调认证相关的,也就是会到CustomerRealm中的认证部分
        try{
            subject.login(new UsernamePasswordToken(username,password));//登录认证
            return "redirect:/index.jsp";//登录成功,用户信息会放在shiro的缓存
        }catch (UnknownAccountException e){
            e.printStackTrace();
            System.out.println("用户名错误");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("密码错误");
        }
        return "redirect:/login.jsp";
    }
}

index.jsp加了一个登出

<body>
        <h1>系统主页</h1>
        <ul>
            <li><a href="">用户管理</a></li>
            <li><a href="">商品管理</a></li>
            <li><a href="">订单管理</a></li>
            <li><a href="">物流管理</a></li>
        </ul>
        <a href="${pageContext.request.contextPath}/user/loginout">退出登录</a>
    </body>

箭头指向的就是改动的
在这里插入图片描述
页面输入 http://localhost:8080/shiro/login.jsp,依然先用下造的假数据xiaoming和123
在这里插入图片描述
点击登录后台会报出用户名错误异常
在这里插入图片描述
用户名正确密码错误,点击登录,后台会出现密码错误异常
在这里插入图片描述
在这里插入图片描述
用户名密码都对,登录成功
在这里插入图片描述
在这里插入图片描述
点击退出登录,那么执行subject.logout()方法,会清除shiro存的用户信息缓存,然后跳转到登录界面

6.2 shiro连接数据库实现MD5+Salt加密认证

我们这节完成注册,注册时对密码进行加密,然后进行登录操作,注册界面也是公共资源,所以也要不拦截,到ShiroConfig配置一下,中间两个加注册的

		map.put("/user/login","anon");//login为公共资源,不要认证,不写这个将login也拦截,那么就会一直在login.jsp界面跳转
        map.put("/user/register","anon");
        map.put("/register.jsp","anon");//注册界面放行
        map.put("/**","authc");//拦截所有,所有都要认证

register.jsp

<%@ page contentType="text/html; charset=utf-8" pageEncoding="UTF-8" isELIgnored="false" %>
<!doctype html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title></title>
    <meta name="keywords" content="">
    <meta name="description" content="">
</head>
<body>
<h1>用户注册界面</h1>

<form action="${pageContext.request.contextPath}/user/register" method="post">
    <tr>
        <td>用户:</td>
        <td><input type="text" name="username"></td>
    </tr>
    <tr>
        <td>密码</td>
        <td><input type="text" name="password"></td>
    </tr>
    <input type="submit" value="注册">
</form>
</body>
</html>

输入地址
在这里插入图片描述
创建数据库shiro,然后在数据库中创建t_user表
在这里插入图片描述
创建成功后导入相关依赖

		<!--mybatis-->
        <dependency>
            <groupId>org.apache.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--Druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.3</version>
        </dependency>

在这里插入图片描述

然后写业务逻辑
UserDao.java

import com.yx.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

@Mapper
@Repository
public interface UserDao {
    void add(User user);
}

UserDaoMapper.xml这个文件创建文件夹别com.yx.mapper创建,要com/yx/mapper才会有层级,不然就是一个目录名字

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yx.dao.UserDao">
    <insert id="add" parameterType="User">
        insert into t_user values(#{id},#{username},#{password},#{salt})
    </insert>
</mapper>

UserService.java

import com.yx.entity.User;

public interface UserService {
    void register(User user);
}

UserServiceImpl.java

import com.yx.dao.UserDao;
import com.yx.entity.User;
import com.yx.utils.SaltUtils;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class UserServiceImpl implements UserService{

    @Autowired
    private UserDao userDao;

    @Override
    public void register(User user) {
        //加密md5+salt+hash
        String salt = SaltUtils.getSalt(6);//生成8位随机盐
        user.setSalt(salt);//保存盐数据
        Md5Hash md5Hash = new Md5Hash(user.getPassword(),salt,1024);
        user.setPassword(md5Hash.toHex());
        userDao.add(user);
    }
}

SaltUtils随即盐生成的代码,自己封装的

import java.util.Random;

//生成随机盐,随机字符串
public class SaltUtils {
    public static String getSalt(int n){
        String code="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*";
        char[] chars = code.toCharArray();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < n; i++) {
            char aChar = chars[new Random().nextInt(chars.length)];
            sb.append(aChar);
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        System.out.println(getSalt(8));
    }
}

UserController中加注册的代码

@Autowired
    private UserService userService;

    @RequestMapping("register")
    public String register(User user){
        try{
            userService.register(user);
            return "redirect:/login.jsp";//注册成功则跳转
        }catch (Exception e){
            e.printStackTrace();
            return "redirect:/register.jsp";
        }

    }

输入 http://localhost:8080/shiro/register.jsp
在这里插入图片描述
点击注册,成功则跳转到登录页面
在这里插入图片描述
数据库中出现注册的数据
在这里插入图片描述
下面来登录认证
首先需要在UserDao.java和UserService.java中加入下面的方法,用于查找数据库中是否存在用户方法

User findByUserName(String username);

UserDaoMapper.xml加入

<select id="findByUserName" parameterType="String" resultType="User">
        select * from t_user
        where username=#{username}
</select>

UserServiceImpl.java进行实现

@Override
    public User findByUserName(String username) {
        return userDao.findByUserName(username);
    }

我们都知道数据在CustomerRealm中做出的假数据,现在我们要从真的数据库中查找数据了,怎么做呢?
我们知道所有对象在SpringBoot中都是以工厂形式加载,所以我们需要获取加载到工厂的UserService这个bean对象
写一个工具类ApplicationContextUtils.java,用于获取UserService这个bean对象,以便用UserService中findByUserName方法

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class ApplicationContextUtils implements ApplicationContextAware {

    private static ApplicationContext context;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }

    //根据bean的名字获取指定的bean对象
    public static Object getBean(String beanName){
        return context.getBean(beanName);
    }
}

CustomerRealm.java

import com.yx.entity.User;
import com.yx.service.UserService;
import com.yx.utils.ApplicationContextUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

//自定义Realm
public class CustomerRealm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String principal = (String) authenticationToken.getPrincipal();
        //工厂中获取UserService对象
        UserService userService = (UserService) ApplicationContextUtils.getBean("userServiceImpl");//UserServiceImpl对应Bean对象名字默认第一个字母小写
        User user = userService.findByUserName(principal);
        if (user != null){
            return new SimpleAuthenticationInfo(principal,user.getPassword(), ByteSource.Util.bytes(user.getSalt()),this.getName());//找到对应用户就会进行比较密码
        }
        return null;
    }
}

ShiroConfig.java配置一下凭证校验匹配器,这样可以让登录表单输入的密码进行md5+salt+hash加密,然后再和数据库中的加密的密码比较

//3、创建自定义realm
    @Bean
    public Realm getRealm(){
        CustomerRealm customerRealm = new CustomerRealm();
        //修改凭证校验匹配器
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //设置加密算法,这样输入的密码才会进行加密,否则就是输入的和数据库中加密的比较,肯定不对
        credentialsMatcher.setHashAlgorithmName("md5");
        credentialsMatcher.setHashIterations(1024);
        customerRealm.setCredentialsMatcher(credentialsMatcher);
        return customerRealm;
    }

输入登录地址 http://localhost:8080/shiro/login.jsp
在这里插入图片描述
在这里插入图片描述
我们也可以再注册一个用户测试一下,在index.jsp加入欢迎您,某用户
index.jsp加一个${msg}
在这里插入图片描述
在这里插入图片描述
重新运行,再进注册界面注册
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
成功

6.3 shiro整合SpringBoot授权

授权就是对菜单功能进行授权,不同用户权限不同,比如普通用户和管理的权限就不同,普通用户只能看到下面三个,管理能操作全部,即也可以看到普通用户,对普通用户进行操作
在这里插入图片描述

CustomerRealm.java对授权部分写对应角色,造假数据,假设yx5411是user普通用户

@Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();
        if ("yx5411".equals(primaryPrincipal)){
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            simpleAuthorizationInfo.addRole("user");
            return simpleAuthorizationInfo;
        }
        return null;
    }

index.jsp改动,加上<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %><shiro:hasRole name="admin"></shiro:hasRole>标签,使得必须具有对应角色才能看到对应功能

<%@ page contentType="text/html; charset=utf-8" pageEncoding="UTF-8" isELIgnored="false" %>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<!doctype html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title></title>
        <meta name="keywords" content="">
        <meta name="description" content="">
    </head>
    <body>
        <h1>系统主页,欢迎您,${msg}</h1>
        <ul>
            <shiro:hasRole name="admin">
                <li><a href="">用户管理</a></li>
            </shiro:hasRole>

            <li><a href="">商品管理</a></li>
            <li><a href="">订单管理</a></li>
            <li><a href="">物流管理</a></li>
        </ul>
        <a href="${pageContext.request.contextPath}/user/loginout">退出登录</a>
    </body>
</html>

我们以yx5411登录,由于是普通用户,所以只有下面三个权限
在这里插入图片描述
CustomerRealm中改成admin用户具有admin角色权限
在这里插入图片描述
重新运行,admin登录
在这里插入图片描述
也可以写多个,就是user,admin都可以看到并操作
在这里插入图片描述
index.jsp

<body>
        <h1>系统主页,欢迎您,${msg}</h1>
        <ul>
            <shiro:hasRole name="admin">
                <li><a href="">用户管理</a>
                    <ul>
                        <shiro:hasPermission name="admin:add:*">
                            <li>添加</li>
                        </shiro:hasPermission>
                        <shiro:hasPermission name="admin:update:*">
                            <li>修改</li>
                        </shiro:hasPermission>
                        <shiro:hasPermission name="admin:delete:*">
                            <li>删除</li>
                        </shiro:hasPermission>
                        <shiro:hasPermission name="admin:find:*">
                            <li>查询</li>
                        </shiro:hasPermission>
                    </ul>
                </li>
            </shiro:hasRole>
            <shiro:hasAnyRoles name="user,admin">
                <li><a href="">商品管理</a></li>
                <li><a href="">订单管理</a></li>
                <li><a href="">物流管理</a></li>
            </shiro:hasAnyRoles>
        </ul>
        <a href="${pageContext.request.contextPath}/user/loginout">退出登录</a>
    </body>

CustomerRealm
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

这样就可以再细致的设置权限,这是标签形式,shiro还提供注解方式@RequiresRoles和@RequiresPermissions,并且我们再加上数据库

总共有三个表:用户、角色、权限,下面用图形式展示三者关系
在这里插入图片描述

shiro数据库中建立表格,id为主键非空自增
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
两个角色,用户和管理员
在这里插入图片描述
下面是用户表比如yx5411的id为1,它是用户角色,那么我们到t_user_role添加这个,admin的id为2,它既是管理又是用户
在这里插入图片描述
在这里插入图片描述
然后数据库搞定就是实体,dao,service一顿操作,由于改动较多,我就不一个一个贴出来了,后面直接给代码+数据库。这里大家可以看视频讲解,链接如下https://www.bilibili.com/video/BV1uz4y197Zm?p=19
在这里插入图片描述
核心sql

SELECT u.id uid,u.username uname,r.id rid,r.name rname
FROM t_user u
LEFT JOIN t_user_role ur ON u.id=ur.userid
LEFT JOIN t_role r ON r.id=ur.roleid
WHERE u.username='admin'

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
不同用户看到的内容不同,授权角色就演示成功,接下来是授权权限的
改动比较多
可参考视频讲解
https://www.bilibili.com/video/BV1uz4y197Zm?p=20
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
核心sql

SELECT p.*,r.name FROM t_role r
LEFT JOIN t_role_permission rp ON r.id=rp.roleid
LEFT JOIN t_permission p ON p.id=rp.permissionid
WHERE r.id=1

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.4 代码+数据库+up主视频讲解

代码+数据库
链接:https://pan.baidu.com/s/1QmRByAzhdReJBI_iixBz2A
提取码:k3le

up主视频
https://www.bilibili.com/video/BV1uz4y197Zm?p=4

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
学习Shiro框架可以按照以下步骤进行: 1. 了解基础概念:首先,你需要了解Shiro的基本概念和术语,例如主体(Subject)、认证(Authentication)、授权(Authorization)、Realm等。可以阅读Shiro的官方文档或者相关的教程来获得这些知识。 2. 安装和配置:安装Shiro框架并进行基本的配置。你可以在Shiro的官方网站上找到安装指南和配置示例。 3. 认证功能:学习如何使用Shiro进行用户认证,包括用户名密码认证、Remember Me功能、多Realm认证等。可以尝试编写简单的认证示例来理解这些功能。 4. 授权功能:学习如何使用Shiro进行用户授权,包括角色授权和权限授权。了解如何定义角色和权限,并且如何在代码中进行授权判断。 5. Session管理:了解Shiro如何管理用户的会话信息,包括会话超时、会话验证等。学习如何使用Shiro提供的Session API来管理会话。 6. 整合框架:如果你使用其他的Java框架,例如Spring或者Spring Boot学习如何将Shiro与这些框架进行整合,以便更好地利用Shiro的功能。 7. 安全性优化:深入了解Shiro的安全性能优化技巧,例如密码加密、安全配置、防止常见安全漏洞等。 8. 实战练习:通过编写实际的应用程序来巩固所学的知识。可以尝试开发一个简单的Web应用程序,使用Shiro进行用户认证和授权。 除了官方文档和教程,还可以参考一些优秀的书籍或在线教程,例如《Apache Shiro官方指南》、《深入浅出Shiro安全框架》等。此外,加入Shiro的社区或者论坛,与其他开发者交流经验也是一个很好的学习方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值