Shiro学习文档

news2024/12/28 5:35:17

Shiro

在这里插入图片描述

Java安全框架

1.什么是权限管理

​ 基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而且只能访问自己被授权的资源。

权限管理包括用户身份认证授权两部分,简称认证授权。对于需要访问控制的资源用户首先经过身份认证,认证通过后用户具有该资源的访问权限方可访问。

2.认证

2.1.什么是认证

用户访问系统的控制 控制该用户能不能访问我们的系统

2.2.认证抽象出的对象

  • Subject:主体

  • Principal:身份信息

​ 是主体(subject)进行身份认证的标识,标识必须具有唯一性,如用户名、手机号、邮箱地址等,一个主体可以有多个身份,但是必须有一个主身份(Primary Principal)。

  • credential:凭证信息

​ 是只有主体自己知道的安全信息,如密码、证书等。

  • token:令牌 Token=身份信息+凭证信息

3.授权

3.1.什么是授权

​ 授权,即访问控制,控制谁能访问哪些资源。主体进行身份认证后需要分配权限方可访问系统的资源,对于某些资源没有权限是无法访问的。

3.2.授权抽象出的对象

授权可简单理解为who对what(which)进行How操作:

  • Who,即主体(Subject),主体需要访问系统中的资源。

  • What,即资源(Resource),如系统菜单、页面、按钮、类方法、系统商品信息等。资源包括资源类型和资源实例,比如商品信息为资源类型,类型为t01的商品为资源实例,编号为001的商品信息也属于资源实例。

  • How,权限/许可(Permission),规定了主体对资源的操作许可,权限离开资源没有意义,如用户查询权限、用户添加权限、某个类方法的调用权限、编号为001用户的修改权限等,通过权限可知主体对哪些资源都有哪些操作许可。

权限分为粗颗粒和细颗粒,粗颗粒权限是指对资源类型的权限,细颗粒权限是对资源实例的权限。

4.权限模型

请添加图片描述

认证授权的过程

  • 1.用户要认证通过

  • 2.授权(用户能看到什么样的页面)

    • 2.1 根据用户查询用户对应的角色
    • 2.2 根据角色查询角色对 应的权限
    • 2.3 根据用户的权限渲染页面

5.权限控制方案

用户拥有了权限即可操作权限范围内的资源,系统不知道主体是否具有访问权限需要对用户的访问进行控制。

5.1 基于角色的访问控制

​ RBAC基于角色的访问控制(Role-Based Access Control)是以角色为中心进行访问控制,比如:主体的角色为总经理可以查询企业运营报表,查询员工工资信息等,访问控制流程如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WgVx38HP-1674897822167)(img\wps1.png)]

上图中的判断逻辑代码可以理解为:

if(主体.hasRole(“总经理角色id”)){

​ 查询工资

}

缺点:以角色进行访问控制粒度较粗,如果上图中查询工资所需要的角色变化为总经理和部门经理,此时就需要修改判断逻辑为“判断主体的角色是否是总经理或部门经理”,系统可扩展性差。

修改代码如下:

if(主体.hasRole(“总经理角色id”) || 主体.hasRole(“部门经理角色id”)){

​ 查询工资

}

5.2 基于资源(权限)的访问控制

​ RBAC基于资源的访问控制(Resource-Based Access Control)是以资源为中心进行访问控制,比如:主体必须具有查询工资权限才可以查询员工工资信息等,访问控制流程如下:

上图中的判断逻辑代码可以理解为:

if(主体.hasPermission(“查询工资权限标识”)){

​ 查询工资

}

优点:系统设计时定义好查询工资的权限标识,即使查询工资所需要的角色变化为总经理和部门经理也只需要将“查询工资信息权限”添加到“部门经理角色”的权限列表中,判断逻辑不用修改,系统可扩展性强。

6.什么是Shiro

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

Apache Shiro™ is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management. With Shiro’s easy-to-understand API, you can quickly and easily secure any application – from the smallest mobile applications to the largest web and enterprise applications.

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。

7.为什么要学shiro

​ 既然shiro将安全认证相关的功能抽取出来组成一个框架,使用shiro就可以非常快速的完成认证、授权等功能的开发,降低系统成本。

​ shiro使用广泛,shiro可以运行在web应用,非web应用,集群分布式应用中越来越多的用户开始使用shiro。

​ java领域中spring security(原名Acegi)也是一个开源的权限管理框架,但是spring security依赖spring运行,而shiro就相对独立,最主要是因为shiro使用简单、灵活,所以现在越来越多的用户选择shiro。

8.Shiro核心架构图

在这里插入图片描述

9.开发Shiro第一个认证程序

9.1.导入jar包

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

8.2.配置Shiro的配置文件

配置文件必须是以.ini结尾的文件

[users]
xiaohei=123456
xiaohuang=111111

9.3.开发第一个认证程序

    //后台认证方法
    public static void testlogin(String username,String password) {

        //初始化安全管理器工厂
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");

        //根据安全管理器工厂初始化安全管理器
        SecurityManager securityManager = factory.createInstance();

        //将安全管理器交给安全工具类
        SecurityUtils.setSecurityManager(securityManager);

        //根据安全工具类获取主体对象
        Subject subject = SecurityUtils.getSubject();

        //创建令牌 token=身份信息(username)+凭证信息(password)
        AuthenticationToken token=new UsernamePasswordToken(username,password);

        //认证
        try {
            subject.login(token);
        } catch (UnknownAccountException e) {
            System.out.println("未知的账号异常   用户名不正确");
        }catch (IncorrectCredentialsException e) {
            System.out.println("不正确的凭证异常   密码错误");
        }

        /*
        * UnknownAccountException: 未知的账号异常   用户名不正确
        * IncorrectCredentialsException:不正确的凭证异常   密码错误
        * */

        boolean authenticated = subject.isAuthenticated();

        System.out.println("认证状态: "+authenticated);
    }

    public static void main(String[] args) {
        testlogin("xiaohei","123456");
    }

注意:

shiro是通过抛异常的形式告诉我们是否认证成功,一般会抛出以下连个异常:

  • UnknownAccountException: 未知的账号异常 用户名不正确

  • IncorrectCredentialsException:不正确的凭证异常 密码错误

  • 更多如下:

    DisabledAccountException(帐号被禁用)

    LockedAccountException(帐号被锁定)

    ExcessiveAttemptsException(登录失败次数过多)

    ExpiredCredentialsException(凭证过期)等

10.源码中的关键类

//抽象类
abstract class AuthenticatingRealm
    
//凭证匹配器   比对凭证信息的       默认SimpleCredentialsMatcher 做凭证比对
private CredentialsMatcher credentialsMatcher;

//抽象方法 
protected abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException;
//实现类
public class SimpleAccountRealm extends AuthorizingRealm extends AuthenticatingRealm
    
//实现抽象方法
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    
    //强转
    UsernamePasswordToken upToken = (UsernamePasswordToken) token;
    //upToken.getUsername()  获取用户名
    
    //getUser  User user=queryByUsername(username)
    SimpleAccount account = getUser(upToken.getUsername());
    
    if (account != null) {
        if (account.isLocked()) {
            throw new LockedAccountException("Account [" + account + "] is locked.");
        }
        if (account.isCredentialsExpired()) {
            String msg = "The credentials for account [" + account + "] are expired";
            throw new ExpiredCredentialsException(msg);
        }
    }
    return account;
}

//根据用户名(身份信息)获取用户对象
protected SimpleAccount getUser(String username) {
    //加读锁
    USERS_LOCK.readLock().lock();
    try {
        
        //this.users = new LinkedHashMap<String, SimpleAccount>();
        //0 xiaohei  123456
        //1 xiaohuang 111111
        
        
        //根据用户名从Map中取出键值对(封装成一个对象)
        return this.users.get(username);
    } finally {
        USERS_LOCK.readLock().unlock();  //解锁
    }
}
//默认凭证匹配器
SimpleCredentialsMatcher  
 //比对密码   equals
 public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
    	//从token中获取凭证信息
        Object tokenCredentials = getCredentials(token);
    	//从info中获取凭证信息
        Object accountCredentials = getCredentials(info);
   
        return equals(tokenCredentials, accountCredentials);
}    

11.认证连接数据库

1.自定义一个Realm类

extends AuthenticatingRealm抽象类,实现doGetAuthenticationInfo抽象方法

public class MyRealm extends AuthenticatingRealm {

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        System.out.println("----");
        //强转
        /*UsernamePasswordToken upToken = (UsernamePasswordToken) token;

        String principals = (String) upToken.getPrincipal();

        String usernames = upToken.getUsername();*/

        //强转
        String usename = (String) token.getPrincipal();

        //查询数据库
        //User u=queryByUsername(username)
        //new User("1","xiaohei","123456")

        //SimpleAccount simpleAccount = new SimpleAccount();

        AuthenticationInfo info =null;

        if(usename.equals("xiaohei")){
            //根据数据库查询的数据封装info对象
            info =new SimpleAuthenticationInfo("xiaohei","123456",this.getName());
        }
        return info;
    }

}

2.配置shiro的配置文件

[main]

#配置自定义Realm
myrealm=com.baizhi.realm.MyRealm

#将自定义realm交给凭证匹配器
securityManager.realms=$myrealm

12.Shiro加密认证

12.1加密

shiro中支持的加密算法有:MD2,MD5,SHA1,SHA256,SHA384,SHA512

    public static void main(String[] args) {

        //MD5 SHA
        //创建加密算法  参数:明文密码
        //Md5Hash md5Hash = new Md5Hash("111111");
        //创建加密算法  参数:明文密码,随机盐
        //Md5Hash md5Hash = new Md5Hash("111111","abcd");
        //创建加密算法  参数:明文密码,随机盐,散列次数
        //Md5Hash md5Hash = new Md5Hash("111111","abcd",1024);

        Md2Hash md2Hash = new Md2Hash("111111");
        Sha1Hash sha1Hash = new Sha1Hash("111111");
        Sha256Hash sha256Hash = new Sha256Hash("111111");
        Sha384Hash sha384Hash = new Sha384Hash("111111");
        Sha512Hash sha512Hash = new Sha512Hash("111111");

        //加密
        String str = md2Hash.toHex();
        String str1 = sha1Hash.toHex();
        String str2 = sha256Hash.toHex();
        String str3 = sha384Hash.toHex();
        String str4 = sha512Hash.toHex();

        System.out.println(str);
        System.out.println(str1);
        System.out.println(str2);
        System.out.println(str3);
        System.out.println(str4);


        /*
        * 96e79218965eb72c92a549dd5a330112  111111
        * f1293bcae648b20fb3329c21b9af1638  abcd 111111
        * c3f2b09474f65a0bb8eda78e3682955f  abcd 111111 1024
        * */

        /*
        Md5Hash:     96e79218 965eb72c 92a549dd 5a330112  32位16进制数
        md2Hash:     43f44d2e 244d26cc e9272c71 b28138dc
        sha1Hash:    3d4f2bf0 7dc1be38 b20cd6e4 6949a107 1f9d0e3d  40
        sha256Hash:  bcb15f82 1479b4d5 772bd0ca 866c00ad 5f926e35 80720659 cc80d39c 9d09802a  64
        sha384Hash:  1b0268a 40ae44c012946c974d60bf5291e7bb7c63cdb72a904d9283e3dc0a34de9afebe4035665768aaa503a4e7a30c3  128
        sha512Hash:  b0412597dcea813655574dc54a5b74967cf85317f0332a2591be7953a016f8de56200eb37d5ba593b1e4aa27cea5ca27100f94dccd5b04bae5cadd4454dba67d 156
        *
        * */

    }

12.2配置加密算法

#方案一:
#配置凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.Md5CredentialsMatcher
    #设置散列次数
    credentialsMatcher.hashIterations=1024
    
#方案二:
#配置凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
    #设置散列次数
    credentialsMatcher.hashIterations=1024
    #设置加密算法
    credentialsMatcher.hashAlgorithmName=MD5


#将凭证匹配器交给自定义Realm
myrealm.credentialsMatcher=$credentialsMatcher

12.3.加密认证

//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

    System.out.println("----");
    //强转
    UsernamePasswordToken upToken = (UsernamePasswordToken) token;
    //获取用户名
    String username = upToken.getUsername();

    //查询数据库
    //User u=queryByUsername(username)
    //new User("1","xiaohei","c3f2b09474f65a0bb8eda78e3682955f","abcd")

    AuthenticationInfo info =null;

    if(username.equals("xiaohei")){
        //根据数据库查询的数据封装info对象   
        info =new SimpleAuthenticationInfo(
            "xiaohei",  //用户名
            "c3f2b09474f65a0bb8eda78e3682955f",  //密文密码
            ByteSource.Util.bytes("abcd"), //随机盐
            this.getName()
        );
    }
    return info;
}

13.授权

13.1实现授权方法

extends AuthorizingRealm抽象类,实现doGetAuthorizationInfo抽象方法

//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    //获取用户主身份
    String username = (String) principals.getPrimaryPrincipal();

    //数据库查询
    //根据用户名插叙该用户有哪些角色  角色集合  admin  sAdmin
    //根据角色查询用户有哪些权限   权限集合
    // admin(user:query  user:update category:query category:delete category:update category:add)
    // sAdmin(admin:query admin:add admin:delete log:query)


    //admin,sAdmin
    //用户管理
    //  user:query  user:update
    //类别管理
    //视频管理
    //sAdmin
    //管理员管理
    // admin:query

    //财务
    //查询工资
    //老板
    //扣工资

    SimpleAuthorizationInfo info=null;

    if(username.equals("xiaohei")){
        //设置权限配置
        info=new SimpleAuthorizationInfo();

        //给当前主体赋予一个角色
        //info.addRole("admin");
        //给当前主体赋予多个角色
        info.addRoles(Arrays.asList("admin","sAdmin"));

        //给当前主体赋予一个权限
        //info.addStringPermission("user:query");
        //给当前主体赋予多个权限
        info.addStringPermissions(Arrays.asList("user:query","user:update","admin:query","admin:add","log:query"));
    }
    return info;
}

13.2.测试授权

//后台认证方法
    public static void testlogin(String username,String password) {

        //初始化安全管理器工厂
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");

        //根据安全管理器工厂初始化安全管理器
        SecurityManager securityManager = factory.createInstance();

        //将安全管理器交给安全工具类
        SecurityUtils.setSecurityManager(securityManager);

        //根据安全工具类获取主体对象
        Subject subject = SecurityUtils.getSubject();

        //创建令牌 token=身份信息(username)+凭证信息(password)
        AuthenticationToken token=new UsernamePasswordToken(username,password);

        //认证
        try {
            subject.login(token);
        }catch (UnknownAccountException e) {
            System.out.println("未知的账号异常   用户名不正确");
        }catch (IncorrectCredentialsException e) {
            System.out.println("不正确的凭证异常   密码错误");
        }

        /*
        * UnknownAccountException: 未知的账号异常   用户名不正确
        * IncorrectCredentialsException:不正确的凭证异常   密码错误
        * */

        //判断是否认证成功
        boolean authenticated = subject.isAuthenticated();
        System.out.println("认证状态: "+authenticated);

        if(authenticated){
            //获取角色  渲染页面

            //判断当前主体是否有该角色
            //boolean b = subject.hasRole("admin");

            //判断当前猪体是否含有这些角色
            //boolean[] booleans = subject.hasRoles(Arrays.asList("admin", "sAdmin", "super"));

            //判断当前主体是否有这些所有的角色
            boolean b = subject.hasAllRoles(Arrays.asList("admin", "sAdmin"));

            System.out.println("角色授权状态: "+b);

            //判断当前主体是否有该权限
            //boolean permitted = subject.isPermitted("user:query");

            //判断当前主体是否有这些权限
            //boolean[] permitteds = subject.isPermitted("user:query", "admin:add");

            //判断当前主体是否有这些所有权限
            boolean permitted = subject.isPermittedAll("user:query", "admin:add");

            System.out.println("权限授权状态: "+permitted);

        }
    }

    public static void main(String[] args) {
        testlogin("xiaohei","111111");
        //xiaohei  123456
    }

13.3.权限控制方案

基于角色的权限控制

//判断当前主体是否有该角色
boolean b = subject.hasRole("admin");
//判断当前猪体是否含有这些角色
boolean[] booleans = subject.hasRoles(Arrays.asList("admin", "sAdmin", "super"));
//判断当前主体是否有这些所有的角色
boolean b = subject.hasAllRoles(Arrays.asList("admin", "sAdmin"));

基于权限的权限控制

//判断当前主体是否有该权限
boolean permitted = subject.isPermitted("user:query");
//判断当前主体是否有这些权限
boolean[] permitteds = subject.isPermitted("user:query", "admin:add");
//判断当前主体是否有这些所有权限
boolean permitted = subject.isPermittedAll("user:query", "admin:add");

13.4.权限字符串

权限字符串的规则是:“资源标识符:操作:资源实例标识符”,意思是对哪个资源的哪个实例具有什么操作,“:”是资源/操作/实例的分割符,权限字符串也可以使用*通配符。

例子:

用户创建权限:user:create,或user:create:*

用户修改实例001的权限:user:update:001

用户实例001的所有权限:user:*:001

14.Shiro集成SpringBoot

14.1.创建一个springBoot项目

14.2.导入Shiro依赖

springBoot依赖
<!--web支持的jar springboot的启动器-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!--测试支持的jar-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <!-- 只在test测试里面运行 -->
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.4</version>
    <scope>provided</scope>
</dependency>

<!-- 给内嵌tomcat提供jsp解析功能的jar-->
<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>

Shiro依赖
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.7.0</version>
</dependency>

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-web</artifactId>
    <version>1.7.0</version>
</dependency>

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.7.0</version>
</dependency>

14.3.配置项目配置

server:
  port: 9191
  servlet:
    context-path: /shiro
    jsp:
      init-parameters:
        development: true
spring:
  mvc:
    view:
      prefix: /
      suffix: .jsp

14.4.配置ShiroFilter配置

@Configuration
public class Myconf {

    //将Shiro过滤器工厂对象交给Spring工厂管理
    @Bean
    public ShiroFilterFactoryBean getShiroFilter(DefaultWebSecurityManager securityManager){

        //创建Shiro过滤器工厂对象
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();

        //将安全管理器对象交给过滤器工厂
        factoryBean.setSecurityManager(securityManager);

        //设置过滤规则的map
        HashMap<String, String> map = new HashMap<>();

        /*
        * anon  匿名过滤器  配置的资源不用认证就可以访问
        * authc 认证过滤器  配置的所有资源必须要认证通过才能访问
        * */
        //资源路径,过滤器简称
        map.put("/**","authc");
        map.put("/user/login","anon");

        //配置过滤器链(多个过滤器)
        factoryBean.setFilterChainDefinitionMap(map);

        //指定登陆页面的位置
        factoryBean.setLoginUrl("/user/login.jsp");

        return factoryBean;
    }

    //将安全管理器对象交给Spring工厂管理
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(){
        //创建安全管理器对象
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
        return securityManager;
    }
}

14.5.Shiro的过滤器

过滤器简称对应的java类
anonorg.apache.shiro.web.filter.authc.AnonymousFilter
authcorg.apache.shiro.web.filter.authc.FormAuthenticationFilter
authcBasicorg.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
permsorg.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
portorg.apache.shiro.web.filter.authz.PortFilter
restorg.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
rolesorg.apache.shiro.web.filter.authz.RolesAuthorizationFilter
sslorg.apache.shiro.web.filter.authz.SslFilter
userorg.apache.shiro.web.filter.authc.UserFilter
logoutorg.apache.shiro.web.filter.authc.LogoutFilter

注意:

anon,authcBasic,auchc,user是认证过滤器,

perms,roles,ssl,rest,port是授权过滤器

14.6.认证

1.登陆页面

<%@page pageEncoding="UTF-8" isELIgnored="false"  %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:set var="path" value="${pageContext.request.contextPath}"/>
    
<!doctype html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    <body>
        <div align="center">
            <div style="border: 3px #cad solid;width: 300px;height: 200px" >
                <form method="post" action="${path}/user/login"><br><br>
                    用户名:<input type="text" name="username" /><br><br>&emsp;码:<input type="password" name="password"/><br><br>
                    <input type="submit" value="登陆"/><br><br>
                </form>
            </div>
        </div>
    </body>
</html>

2.登陆方法

@RequestMapping("login")
public String login(String username,String password){

    @RequestMapping("login")
    public String login(String username,String password){
        System.out.println("username: "+username);

        //获取主体对象
        Subject subject = SecurityUtils.getSubject();

        //封装token
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);

        String message=null;
        try {
            //认证
            subject.login(token);
            return "redirect:/main/main.jsp";
        }catch (UnknownAccountException e){
            message="用户名不正确";
            System.out.println("认证结果: "+message);
            return "redirect:/user/login.jsp";
        }catch (IncorrectCredentialsException e){
            message="密码不正确";
            System.out.println("认证结果: "+message);
            return "redirect:/user/login.jsp";
        }
    }
}

3.主体认证

自定义一个Realm类,继承AuthorizingRealm实现doGetAuthenticationInfo方法

//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

    String username = (String) token.getPrincipal();
    //User("1","xiaohei","c3f2b09474f65a0bb8eda78e3682955f","abcd")

    AuthenticationInfo info =null;
    if(username.equals("xiaohei")){
        info =new SimpleAuthenticationInfo(
            username,
            "c3f2b09474f65a0bb8eda78e3682955f",
            ByteSource.Util.bytes("abcd"),
            this.getName()
        );
    }
    return info;
}

4.配置认证相关配置

  • 1.自定义Relam

  • 2.将自定义Realm交给安全管理器

  • 3.配置凭证匹配器 设置加密算法 散列次数

  • 4.将凭证匹配器交给自定义Realm

@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
    //创建安全管理器对象
    DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();

    //将自定义Realm交给安全管理器
    securityManager.setRealm(myRealm);
    return securityManager;
}

//将自定义Realm对象交给Spring工厂管理
@Bean
public MyRealm getMyRealm(HashedCredentialsMatcher credentialsMatcher){
    //创建自定义的Realm对象
    MyRealm myRealm = new MyRealm();


    //将凭证匹配器给自定义的Realm
    myRealm.setCredentialsMatcher(credentialsMatcher);

    return myRealm;
}

//将凭证匹配器对象交给Spring工厂管理
@Bean
public HashedCredentialsMatcher getHashedCredentialsMatcher(){

    //创建凭证匹配器
    HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
    credentialsMatcher.setHashAlgorithmName("MD5"); //加密算法
    credentialsMatcher.setHashIterations(1024);  //散列次数

    return credentialsMatcher;
}

5.退出

5.1.退出页面

<a href="${path}/user/logout">退出</a>

5.2.退出程序

@RequestMapping("logout")
public String logout(){
    //获取主体对象
    Subject subject = SecurityUtils.getSubject();
    //调用退出登录方法
    subject.logout();
    return "redirect:/user/login.jsp";
}

5.3.使用退出过滤器退出

<a href="${path}/logout">退出</a>
//配置退出过滤器  具体的退出代码Shiro已经实现
map.put("/logout","logout");

14.7.Shiro中的标签

导入Shiro的标签库

<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

Shiro中的标签

<!--获取身份信息-->
<shiro:principal/>

<!--认证之后展示的内容-->
<!--记住我登陆不算是认证通过 没有调用subject.login(token)-->
<shiro:authenticated></shiro:authenticated>
<!--没有认证展示的内容-->
<shiro:notAuthenticated></shiro:notAuthenticated>

<!--认证成功之后展示的内容/记住我登陆-->
<shiro:user></shiro:user>
<!--没有认证成功之后展示的内容  游客访问到的内容-->
<shiro:guest></shiro:guest>

14.9 配置Shiro中Session 的过期时间

在shiro中自带SessionManager ,session默认过期时间时30分钟

设置过期时间

//将Session管理器对象交给Spring工厂管理
@Bean
public DefaultWebSessionManager getDefaultWebSessionManager(){
    //创建Session管理器对象
    DefaultWebSessionManager sessionManager=new DefaultWebSessionManager();

    //设置session过期时间  参数:long类型的过期时间单位时毫秒
    sessionManager.setGlobalSessionTimeout((1*1000)*60*2);

    return sessionManager;
}

将Session管理器交给安全管理器

//将Session管理器交给安全管理器
securityManager.setSessionManager(sessionManager);

14.10.记住我的登陆

1.页面加入记住我复选框

<form action="${path}/user/login" method="post"/><br><br>
    用户名:<input name="username" type="text"/><br><br>&emsp;码:<input name="password" type="password"/><br><br>
    <input type="checkbox" name="rememberme" value="1">记住我7天</input><br><br>
    <input type="submit" value="点我登陆"/>
</form>

2.开启记住我

@RequestMapping("login")
public String login(String username,String password,Integer rememberme){

    System.out.println("==rememberme "+rememberme);

    //根据安全工具类获取主体对象
    Subject subject = SecurityUtils.getSubject();

    //创建token对象 参数:身份信息,凭证信息
    UsernamePasswordToken token = new UsernamePasswordToken(username, password);

    //判断是否要记住我登陆
    if(rememberme!=null && rememberme==1){
        System.out.println("====");
        //是否开启记住我
        token.setRememberMe(true);
    }

    //认证
    try {
        subject.login(token);

        boolean authenticated = subject.isAuthenticated();
        System.out.println("认证状态:"+authenticated);

        return "redirect:/main/main.jsp";
    } catch (UnknownAccountException e) {
        System.out.println("未知的账户异常 用户名不正确");
        return "redirect:/login/login.jsp";
    }catch (IncorrectCredentialsException e){
        System.out.println("不正确的凭证异常  密码错误");
        return "redirect:/login/login.jsp";
    }
}

3.配置记住我过期时间

//将记住我管理器交给Spring工厂管理
@Bean
public CookieRememberMeManager getCookieRememberMeManager(SimpleCookie cookie){
    //创建记住我管理器
    CookieRememberMeManager rememberMeManager=new CookieRememberMeManager();
    //将Cookie 交给记住我管理器
    rememberMeManager.setCookie(cookie);
    return rememberMeManager;
}

//将Shiro中的Cookie对象交给Spring工厂管理
@Bean
public SimpleCookie getSimpleCookie(){
    SimpleCookie cookie =new SimpleCookie();
    //cookie的名称,对应的是前端checkbox中name属性的值  name="rememberme"
    cookie.setName("rememberme");
    //设置记住我cookie的失效时间   参数:秒
    cookie.setMaxAge(60*2);
    return cookie;
}

将记住我管理器交给安全管理器

//将记住我管理器交给安全管理器
securityManager.setRememberMeManager(rememberMeManager);

4.配置记住我过滤器

map.put("/**","user"); //记住我过滤器,记住我登陆就可以访问

14.11.授权

14.11.1实现授权方法

继承AuthorizingRealm实现doGetAuthorizationInfo方法

//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

    //获取主身份
    String username = (String)principalCollection.getPrimaryPrincipal();

    //根据身份信息查询角色  角色集合
    //根据角色查询权限   权限集合
    // admin(user:query  user:update category:query category:delete category:update category:add)
    // sAdmin(admin:query admin:add admin:delete log:query)

    SimpleAuthorizationInfo info=null;
    if(username.equals("xiaohei")){
        //设置主体的角色和权限
        info=new SimpleAuthorizationInfo();

        //设置角色
        info.addRoles(Arrays.asList("admin","sAdmin"));
        //设置权限
        info.addStringPermissions(Arrays.asList("user:query","user:update","admin:query","admin:add"));
    }
    return info;
}

授权的标签

<!--判断当前主体有这些其中一个角色就展示-->
<shiro:hasAnyRoles name="admin,sAdmin"></shiro:hasAnyRoles>
<!--判断当前主体是否由该角色-->
<shiro:hasRole name="sAdmin"></shiro:hasRole>
<!--判断当前主体没有该角色-->
<shiro:lacksRole name="super"></shiro:lacksRole>
<!--判断当前主体没有有该权限时展示-->
<shiro:lacksPermission name=""></shiro:lacksPermission>
<!--判断当前主体有该权限时展示-->
<shiro:hasPermission name="user:add"></shiro:hasPermission>

配置授权过滤器

//角色过滤器
map.put("/user/add","roles[userA]");
//权限过滤器
map.put("/user/add","perms[user:add]");

14.12.缓存

1.导入jar包

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>1.7.0</version>
</dependency>

2.配置缓存

//将缓存交给Spring工厂
@Bean
public CacheManager getCacheManager(){

    //1.配置缓存
    CacheManager cacheManager = new EhCacheManager();
    //2.将缓存配置给myRealm  注意:在Realm中配置
    myRealm.setCacheManager(cacheManager);
    
    return cacheManager;
}

14.13.示例

1.配置

package com.baizhi.conf;

import com.baizhi.realm.MyRealm;
import com.sun.org.apache.bcel.internal.generic.NEW;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
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 javax.annotation.Resource;
import java.util.HashMap;

@Configuration
public class ShiroFilterConf {

    //将shiro过滤器工厂交给Spring工厂
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager){

        //创建shiro过滤器工厂
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        //将安全管理器交给shiro过滤器工厂
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        HashMap<String, String> map = new HashMap<>();

        //FormAuthenticationFilter  authc   认证过滤器
        //AnonymousFilter  anon    匿名过滤器

        map.put("/**","authc");
        map.put("/user/login","anon");
        map.put("/main/main.jsp","anon");

        //指定拦截跳转的login页面
        shiroFilterFactoryBean.setLoginUrl("/main/login.jsp");

        //定义一个过滤器链
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);

        return shiroFilterFactoryBean;
    }

    //将安全管理器交给Spring工厂
    @Bean
    public SecurityManager getSecurityManager(MyRealm myRealm){

        //创建安全管理器
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        //将自定义Realm配置到安全管理器中
        securityManager.setRealm(myRealm);

        return securityManager;
    }

    //将自定义Realm交给Spring工厂
    @Bean
    public MyRealm getMyRealm(HashedCredentialsMatcher credentialsMatcher,CacheManager cacheManager){

        MyRealm myRealm = new MyRealm();

        //配置缓存
        myRealm.setCacheManager(cacheManager);

        //将凭证匹配器交给自定义Realm
        myRealm.setCredentialsMatcher(credentialsMatcher);

        return myRealm;
    }

    //将凭证匹配器交给Spring工厂
    @Bean
    public HashedCredentialsMatcher getHashedCredentialsMatcher(){

        //创建凭证匹配器
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();

        //设置使用的加密算法
        credentialsMatcher.setHashAlgorithmName("MD5");

        //设置散列次数
        credentialsMatcher.setHashIterations(1024);

        return credentialsMatcher;
    }

    //将缓存交给Spring工厂
    @Bean
    public CacheManager getCacheManager(){

        //配置缓存
        CacheManager cacheManager = new EhCacheManager();

        return cacheManager;
    }
}

2.自定义Realm认证授权

package com.baizhi.realm;

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;

import java.util.Arrays;

public class MyRealm extends AuthorizingRealm {

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        System.out.println("===授权===");

        //获取身份信息
        String username = (String) principalCollection.getPrimaryPrincipal();

        //根据身份信息查询  角色  权限
        //根据角色查权限

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        if(username.equals("xiaohei")){

            //将查询出来的角色放入授权信息中
            info.addRoles(Arrays.asList("user","admin"));
            //将查询出来的权限放入授权信息中
            info.addStringPermissions(Arrays.asList("user:query","user:update","admin:query"));
        }

        return info;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        System.out.println("===认证===");

        //获取身份信息
        String username = (String) authenticationToken.getPrincipal();

        //去数据库查  根据身份信息查询用户  省略

        if(username.equals("xiaohei")){
            AuthenticationInfo info=new SimpleAuthenticationInfo("xiaohei","c3f2b09474f65a0bb8eda78e3682955f", ByteSource.Util.bytes("abcd"),this.getName());
            return info;
        }

        return null;
    }
}

3.Controller

package com.baizhi.controller;

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

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

    @RequestMapping("login")
    public String login(String username,String password){
        System.out.println("username: "+username);
        System.out.println("password: "+password);

        //根据安全工具类获取主体
        Subject subject = SecurityUtils.getSubject();

        //将主体放入token令牌中
        AuthenticationToken token=new UsernamePasswordToken(username,password);

        try {
            //认证
            subject.login(token);

            return "redirect:/main/main.jsp";
        } catch (UnknownAccountException e) {
            System.out.println("身份认证失败");
            return "redirect:/main/login.jsp";
        }catch (IncorrectCredentialsException e) {
            System.out.println("密码错误");
            return "redirect:/main/login.jsp";
        }
    }

    @RequestMapping("logout")
    public String logout(){

        //根据安全工具类获取主体
        Subject subject = SecurityUtils.getSubject();

        //登出
        subject.logout();

        System.out.println("退出");
        return "redirect:/main/login.jsp";
    }
}

4.jsp

<%@page pageEncoding="UTF-8" contentType="text/html;UTF-8" isELIgnored="false" %>
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Main</title>
</head>
<body align="center">
    <h1>欢迎来到主页面</h1>

    <div align="right">

        <%--认证成功展示内容--%>
        <shiro:authenticated>
            欢迎来到主页面,您好<strong><span style="color:red"><shiro:principal/></span></strong><a href="${pageContext.request.contextPath}/user/logout">退出</a><br>

            <div align="left">



                <ul>
                    <%--判断该主体是否有该角色--%>
                    <shiro:hasRole name="user">
                        <li>轮播图管理</li><br>
                        <li>专辑管理</li><br>
                        <li>文章管理</li><br>
                    </shiro:hasRole>

                    <%--判断该主体是否有其中一个角色--%>
                    <shiro:hasAnyRoles name="admin,superAdmin">
                        <li>用户管理</li><br>

                        <%--判断该主体是否有该权限--%>
                        <shiro:hasPermission name="user:query">
                            <button ></button>
                        </shiro:hasPermission><br>
                        <shiro:hasPermission name="user:add">
                            <button ></button>
                        </shiro:hasPermission><br>
                        <shiro:hasPermission name="user:update">
                            <button ></button>
                        </shiro:hasPermission><br>
                        <shiro:hasPermission name="user:delete">
                            <button ></button>
                        </shiro:hasPermission><br>

                    </shiro:hasAnyRoles>

                    <shiro:hasRole name="superAdmin">
                        <li>管理员管理</li><br>
                    </shiro:hasRole>
                </ul>
            </div>


        </shiro:authenticated>

        <%--未认证成功展示内容--%>
        <shiro:notAuthenticated>
            您还没有<a href="${pageContext.request.contextPath}/main/login.jsp">登陆</a>,如果想浏览更多信息请登录

        </shiro:notAuthenticated>
    </div>
</body>
</html>

14.Shiro连接数据库

1.准备数据库表

/*
Navicat MySQL Data Transfer

Source Server         : MySQL
Source Server Version : 50528
Source Host           : localhost:3306
Source Database       : shiro

Target Server Type    : MYSQL
Target Server Version : 50528
File Encoding         : 65001

Date: 2019-08-13 16:39:03
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for s_admin
-- ----------------------------
DROP TABLE IF EXISTS `s_admin`;
CREATE TABLE `s_admin` (
  `admin_id` varchar(50) NOT NULL DEFAULT '',
  `username` varchar(50) DEFAULT NULL,
  `password` varchar(50) DEFAULT NULL,
  `salt` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`admin_id`),
  UNIQUE KEY `s_admin_admin_id_uindex` (`admin_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of s_admin
-- ----------------------------
INSERT INTO `s_admin` VALUES ('1', 'nanan', 'a2c9ec06b8c0a2be811dfd47be6e5f82', 'asdfaf');
INSERT INTO `s_admin` VALUES ('2', 'bobo', 'c3f2b09474f65a0bb8eda78e3682955f', 'abcd');

-- ----------------------------
-- Table structure for s_admin_role
-- ----------------------------
DROP TABLE IF EXISTS `s_admin_role`;
CREATE TABLE `s_admin_role` (
  `id` varchar(50) DEFAULT NULL,
  `admin_id` varchar(50) DEFAULT NULL,
  `role_id` varchar(50) DEFAULT NULL,
  UNIQUE KEY `s_admin_role_id_uindex` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of s_admin_role
-- ----------------------------
INSERT INTO `s_admin_role` VALUES ('1', '1', '2');
INSERT INTO `s_admin_role` VALUES ('2', '1', '1');
INSERT INTO `s_admin_role` VALUES ('3', '1', '4');
INSERT INTO `s_admin_role` VALUES ('4', '1', '3');

-- ----------------------------
-- Table structure for s_authority
-- ----------------------------
DROP TABLE IF EXISTS `s_authority`;
CREATE TABLE `s_authority` (
  `authority_id` varchar(50) DEFAULT NULL,
  `authority_name` varchar(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of s_authority
-- ----------------------------
INSERT INTO `s_authority` VALUES ('1', 'admin:query');
INSERT INTO `s_authority` VALUES ('2', 'admin:delete');
INSERT INTO `s_authority` VALUES ('3', 'admin:update');
INSERT INTO `s_authority` VALUES ('4', 'admin:insert');

-- ----------------------------
-- Table structure for s_role
-- ----------------------------
DROP TABLE IF EXISTS `s_role`;
CREATE TABLE `s_role` (
  `role_id` varchar(50) DEFAULT NULL,
  `role_name` varchar(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of s_role
-- ----------------------------
INSERT INTO `s_role` VALUES ('1', 'common');
INSERT INTO `s_role` VALUES ('2', 'super');
INSERT INTO `s_role` VALUES ('3', 'admin');
INSERT INTO `s_role` VALUES ('4', 'user');

-- ----------------------------
-- Table structure for s_role_authority
-- ----------------------------
DROP TABLE IF EXISTS `s_role_authority`;
CREATE TABLE `s_role_authority` (
  `id` varchar(50) DEFAULT NULL,
  `role_id` varchar(50) DEFAULT NULL,
  `authority_id` varchar(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of s_role_authority
-- ----------------------------
INSERT INTO `s_role_authority` VALUES ('1', '2', '1');
INSERT INTO `s_role_authority` VALUES ('2', '2', '2');
INSERT INTO `s_role_authority` VALUES ('3', '2', '3');
INSERT INTO `s_role_authority` VALUES ('4', '2', '4');

2.配置实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Admin {
    private String admin_id;
    private String username;
    private String password;
    private String salt;

    //关系属性  角色集合
    private List<Role> roles;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Role {

    private String role_id;
    private String role_name;

    //关系集合  权限集合
    private List<Authority> authorities;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Authority {

    private String authority_id;
    private String authority_name;
}

2.配置DAO

public interface AdminDao {

    Admin queryByUsername(String username);

    Admin queryByUsernames(String username);
}

3.配置Mapper文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="com.baizhi.dao.AdminDao">
<!--
    private String admin_id;
    private String username;
    private String password;
    private String salt;

    private String role_id;
    private String role_name;

    private String authority_id;
    private String authority_name;
-->
    <resultMap id="queryMap" type="Admin">
        <id column="aadminId" property="admin_id" />
        <result column="ausername" property="username" />
        <result column="apassword" property="password" />
        <result column="asalt" property="salt" />
        <collection property="roles" javaType="list" ofType="Role">
            <id column="rroleId" property="role_id" />
            <result column="rroleName" property="role_name" />
            <collection property="authorities" javaType="list" ofType="Authority">
                <id column="auauthorityId" property="authority_id" />
                <result column="auauthorityName" property="authority_name" />
            </collection>
        </collection>
    </resultMap>

    <select id="queryByUsernames" resultMap="queryMap">
        select a.admin_id aadminId ,a.username ausername,a.password apassword,a.salt asalt,
               r.role_id rroleId,r.role_name rroleName,
               au.authority_id auauthorityId,au.authority_name auauthorityName
          from s_admin a
          left join s_admin_role ar on a.admin_id=ar.admin_id
          left join s_role r on ar.role_id=r.role_id
          left join s_role_authority ra on r.role_id=ra.role_id
          left join s_authority au on ra.authority_id= au.authority_id
        where username=#{username}
    </select>

    <select id="queryByUsername" resultType="Admin">
        select * from s_admin where username=#{username}
    </select>
</mapper>

4.认证授权连接数据库

package com.baizhi.realm;

import com.baizhi.entity.Admin;
import com.baizhi.entity.Authority;
import com.baizhi.entity.Role;
import com.baizhi.service.AdminService;
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;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class MyRealm extends AuthorizingRealm {

    @Resource
    AdminService adminService;

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        System.out.println("===授权===");

        //获取身份信息
        String username = (String) principalCollection.getPrimaryPrincipal();

        //创建角色集合
        ArrayList<String> roles = new ArrayList<>();

        //创建权限集合
        ArrayList<String> permissions = new ArrayList<>();

        //根据身份信息查询  角色  权限
        //根据角色查权限
        Admin admin = adminService.queryByUsernames(username);

        //获取对应主体的角色集合
        List<Role> roleList = admin.getRoles();

        //判断角色集合是否为空
        if(roleList.size()!=0){

            //遍历角色集合
            for (Role role : roleList) {

                //根据角色对象获取角色名称
                String role_name = role.getRole_name();

                //将角色名称放入角色集合
                roles.add(role_name);

                //根据角色对象获取该角色下的所有权限
                List<Authority> authorityList = role.getAuthorities();

                //判断权限集合是否为空
                if(authorityList.size()!=0){
                    //遍历权限集合
                    for (Authority authority : authorityList) {

                        //根据权限对象获取权限名称
                        String authority_name = authority.getAuthority_name();

                        //将权限名称放入权限集合
                        permissions.add(authority_name);
                    }
                }
            }
        }

        //遍历封装好的角色集合
        for (String name : roles) {
            System.out.println("==角色名称: "+name);
        }

        //遍历封装好的权限集合
        for (String name : permissions) {
            System.out.println("==权限名称: "+name);
        }

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        //将查询出来的角色放入授权信息中
        info.addRoles(roles);
        //将查询出来的权限放入授权信息中
        info.addStringPermissions(permissions);

        return info;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        System.out.println("===认证===");

        //获取身份信息
        String username = (String) authenticationToken.getPrincipal();

        //去数据库查  根据身份信息查询用户  省略
        Admin admin = adminService.queryByUsername(username);
        AuthenticationInfo info=null;
        //判断查询到的用户是否为空
        if(admin!=null){
            info = new SimpleAuthenticationInfo(admin.getUsername(),admin.getPassword(), ByteSource.Util.bytes(admin.getSalt()),this.getName());
        }
        return info;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/182985.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

oracle mysql postgresql opengauss 批量kill session

oracle alter system kill session sid,serial# immed; &#xff08;根据v$session中查出sid和serial#进行替换&#xff09; 这里提供一个常用脚本&#xff0c;支持跨实例kill会话 &#xff08;替换&1条件或放到脚本调用都行&#xff09; select alter system kill sessi…

Dubbo 简介

Apache Dubbo 是一款 RPC 服务开发框架&#xff0c;用于解决微服务架构下的服务治理与通信问题&#xff0c;官方提供了 Java、Golang 等多语言 SDK 实现。使用 Dubbo 开发的微服务原生具备相互之间的远程地址发现与通信能力&#xff0c; 利用 Dubbo 提供的丰富服务治理特性&…

嵌入式工程师的2022 || 2023

因为一些个人关系&#xff0c;2022年初我从北京回到了石家庄。在找工作&#xff0c;包括后续的研发工作中&#xff0c;不同地点的经历在对比中我逐渐总结出了一些经验。关于“人”方面的感悟我就不赘述了&#xff0c;下面主要在这里总结一些找工作&#xff0c;做工作的经验&…

八、迁移学习和多任务学习

文章目录1、迁移学习2、多任务学习3、端到端学习THE END1、迁移学习 \qquad迁移学习是将某个任务学习到的知识(神经网络的参数信息)迁移到另外一个相似的任务中使用&#xff0c;从而重复利用相似任务学习共同之处&#xff0c;节省模型训练的时间&#xff0c;提高模型的训练效率…

一名普通22届本科毕业生|前端程序员|22年年终总结

文章目录22年上半年&#xff1a;最后的学生时光隔离实习币基金迷茫困惑难受不要去想人生意义读书景点环境的力量再次隔离返校入职前的学习22年下半年&#xff1a;上班工作生活总结本来准备在22年年末写的&#xff0c;奈何那段时间工作太忙没抽出时间。现在是23年的1月27日&…

paddleOCR代码工程的MD模式改造

一、下载cmake_3.22.3&#xff0c;用于生成vs工程 Index of /files/v3.22 下载完成&#xff0c;解压文件&#xff0c;打开cmake-gui.exe&#xff0c;即可使用&#xff1a; 二、下载Git&#xff08;Git-2.36.0-64-bit.exe&#xff09;并按照默认路径安装&#xff0c;cmake需调用…

使用Moment格式化时间出现时间差

诶嘿&#xff0c;很离奇。前些天后端老哥给我说我这时间展示不对。 我就奇了个大怪&#xff0c;就是取的这个字段嘛&#xff0c;怎么肥事&#x1f62d; 看半天发现是时间格式化出的问题。 原代码⬇️&#xff0c;看起来没毛病嘛&#xff0c;值打印出来也与接口里的这个时间一…

到底卡在了哪里,2023年再撒谎网慢就说不过去了

前言互联网下行带来灵魂追问。钱花哪去了&#xff1f;产出在哪里&#xff1f;动辄自建的遮羞布逐步显现&#xff0c;不过自建的成本可能还不是最大的负担&#xff0c;掣肘的可能是把不重要的事情当成了主业来做&#xff0c;比如&#xff1a;互联网比如数字化转型比如研发效率和…

Verilog HDL基本语法规则

⭐本专栏针对FPGA进行入门学习&#xff0c;从数电中常见的逻辑代数讲起&#xff0c;结合Verilog HDL语言学习与仿真&#xff0c;主要对组合逻辑电路与时序逻辑电路进行分析与设计&#xff0c;对状态机FSM进行剖析与建模。 &#x1f525;文章和代码已归档至【Github仓库&#xf…

10大面试必备的排序算法 Python 实现(附源码)

今天给大家分享一篇关于Python实现排序算法的文章&#xff0c;来自GitHub。 排序算法是《数据结构与算法》中最基本的算法之一。 排序算法可以分为内部排序和外部排序&#xff0c;内部排序是数据记录在内存中进行排序&#xff0c;而外部排序是因排序的数据很大&#xff0c;一…

STM32入门基础

GPIO <1>说明 引脚电平&#xff1a;0~3.3V&#xff0c;部分可达到5V(参考引脚定义&#xff0c;带FT的就可以) 同时 GPIO有两个模式 输出模式&#xff1a;进行端口高低电平的输出&#xff0c;用于驱动LED&#xff0c;蜂鸣器等 输入模式&#xff1a;读取端口高低电平…

SimBERT剖析

SimBERT SimBERT&#xff0c;它是以Google开源的BERT模型为基础&#xff0c;基于微软的UniLM思想设计了融检索与生成于一体的任务&#xff0c;来进一步微调后得到的模型&#xff0c;所以它同时具备相似问生成和相似句检索能力。 UniLM UniLM是一个融合NLU和NLG能力的Transfo…

远程桌面控制:SmartCode VNC ViewerX ActiveX 3.10 Crack

SmartCode::ViewerX VNC 查看器 ActiveX 毫不费力地将 VNC 查看器功能添加到您的应用程序 SmartCode ViewerX VNC 查看器 ActiveX 使开发人员可以使用一组直观的 ActiveX 属性和方法完全访问 VNC 查看器功能。借助ViewerX 控件&#xff0c;开发人员可以轻松地为其应用程序提供屏…

将自己写的代码利用git 上传到码云(gitee)或者github----最简洁明了版

前置操作 注册并激活码云账号&#xff08; 注册页面地址&#xff1a;https://gitee.com/signup &#xff09; 生成并配置 SSH 公钥 官方提供的生成并配置公钥的方法点此 创建空白的码云仓库 输入仓库名称之后路径会自动生成 把本地项目上传到码云对应的空白仓库中 如果您是…

MyBatis-Plus快速开始

文章目录介绍特性框架结构传统编程模式快速开始介绍 MyBatis-Plus&#xff08;简称 MP&#xff09;是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。只做增强不做改变的意思是&#xff1a;MP不会影响原生的 M…

[HITCON 2017]SSRFme(perl脚本中get命令执行漏洞)

目录 代码审计 思路 知识补充 PHP中$_SERVER的详细用法 pathinfo() 函数 str_replace() 函数 escapeshellarg peal函数中get命令漏洞 Perl中open命令执行&#xff08;GET&#xff09; 代码审计 <?phpif (isset($_SERVER[HTTP_X_FORWARDED_FOR])) {$http_x_headers…

GuLi商城-项目初始结构创建

GitHub账号和密码 账号&#xff1a;11360XXXXXqq.com 密码&#xff1a;ZH**SH*19**1016 新建仓库&#xff1a; gulimall 记得勾选下Add a README file&#xff0c;上面忘记勾选了&#xff0c;实际建议还是要勾选下 复制路径&#xff1a; 打开IDEA检出项目 创建商品微服务模…

flutter 作为模块引入 iOS 项目

原文 http://summerxx.com/2023/01/28/ios-use-flutter/ 前言: 上篇我讲了下 flutter 环境在 MacOs 下搭建, 今天写下如何在一个成熟的 iOS 项目内引用 flutter, Demo 会放到文章最后哈 上篇 : MacOS 下配置flutter 环境 大致如下: 在项目内创建一个 flutter 模块 新建一个 …

Unity 在URP中显示动态批处理 Dynamic Batching 选项

Unity 在URP中显示动态批处理 Dynamic Batching 选项前言步骤1. 打开 Preferences 设置2. 选择 Core Render Pipeline 选项卡3. 修改 Visibility 为 All Visible4. 打开 Project Settings5. 打开 Graphics 选项卡6. 找到 URP 设置7. 开启 Dynamic Batching鸣谢前言 使用URP时突…

计算机相关专业提升学历的解决方案(本科及以下)

文章目录1、学历与学位的区别1.1 学历与学位的概念&#xff0c;学籍的规则1.2 学历与学位的作用2、正规全日制本科2.1 高考2.2 统招专升本3、继续教育&#xff08;非全日制&#xff09;3.1 自学考试&#xff08;无学籍&#xff09;3.2 成人高考&#xff08;函授&#xff0c;业余…