shiro实战详解(2)

发布时间:2024年01月19日

03 Shiro入门

1.身份认证

1.1基本流程

流程如下:

1、Shiro把用户的数据封装成标识token,token一般封装着用户名,密码等信息

2、使用Subject门面获取到封装着用户的数据的标识token

3、Subject把标识token交给SecurityManager,在SecurityManager安全中心中,SecurityManager

把标识token委托给认证器Authenticator进行身份验证。认证器的作用一般是用来指定如何验证,它规定本次认证用到哪些Realm

4、认证器Authenticator将传入的标识token,与数据源Realm对比,验证token是否合法

1.2案例

1.坐标

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

2.设置shrio-test-01.ini模拟数据库

[users]
jx=123456
djx=654321
hcy=147258

3.test类测试–>通过工厂创建SecurityManager对象,并认证

@Test
    public void show1(){
        //1.创建工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shrio_test_01.ini");
        //2.获取对象
        SecurityManager instance = factory.getInstance();
        //3.绑定当前对象到运行环境
        SecurityUtils.setSecurityManager(instance);
        //4.当前环境获取subject
        Subject subject = SecurityUtils.getSubject();
        //用户
        String username= "jx";
        String userpasswd= "123456";
        //5.获取到令牌
        UsernamePasswordToken token = new UsernamePasswordToken(username, userpasswd);
        //6.登录验证
        subject.login(token);
        System.out.println("----------------"+subject.isAuthenticated());
    }

2.Realm

2.1Realm接口

在这里插入图片描述

2.2认证案例

1.创建MyRealm,继承AuthorizingRealm,实现两个方法

package com.ape.shrio;

import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import java.util.ArrayList;

/**
 * @author jx
 * @version 1.0
 * @since 2023/11/6
 **/
public class MyRealm extends AuthorizingRealm {

	//授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
     return null;
    }
    
	//认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
		
        System.out.println("执行认证操作");
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;

        String username = token.getUsername();
        String userpwd = new String(token.getPassword());

        if ("jx".equals(username) && "123456".equals(userpwd)){
            SimpleAuthenticationInfo myshrio =
                    new SimpleAuthenticationInfo(username, userpwd, "myRealm");//1.安全数据  2.用户密码 3.当前realm
            return  myshrio;
        }else{
            System.out.println("账号密码错误");
            throw new RuntimeException("账号密码错误");
        }
    }
}

2.设置shrio-test-02.ini模拟数据库

[users] # 用户
jx=123456,role1,role2
djx=654321,role2

[roles]  # 角色
role1=user:save,user:update,user:delete
role2=user:find

3.test类测试

 @Test
    public void show(){

        //创建工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shrio_test_02.ini");
        //获取对象
        SecurityManager instance = factory.getInstance();
        //绑定当前对象到运行环境
       SecurityUtils.setSecurityManager(instance);
        //当前环境获取subject
        Subject subject = SecurityUtils.getSubject();
        //用户
       String username = "jx";
       String userpwd = "123456";
        //获取到令牌
        UsernamePasswordToken token = new UsernamePasswordToken(username, userpwd);
        //登录验证
         subject.login(token);
		// 角色,权限
        System.out.println(subject.isAuthenticated());
        System.out.println(subject.hasRole("role1")); //true
        System.out.println(subject.hasRole("role2")); //true
        System.out.println(subject.isPermitted("user:save")); //true
        System.out.println(subject.isPermitted("user:find")); //true
    }
2.3认证授权案例

1.设置shrio-test-03.ini声明myRealm

[main]
# 声明realm
myClass=com.ape.shrio.MyRealm
securityManager.realms=$myClass

2.创建MyRealm,继承AuthorizingRealm,实现重写两个方法

package com.ape.shrio;

import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import java.util.ArrayList;

/**
 * @author jx
 * @version 1.0
 * @since 2023/11/6
 **/
public class MyRealm extends AuthorizingRealm {
	//授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行授权方法");
        String username = (String)principalCollection.getPrimaryPrincipal();

        ArrayList<String> roles = new ArrayList<>();
        roles.add("role1");
        roles.add("role2");

        ArrayList<String> authoriys = new ArrayList<>();
        authoriys.add("user:save");
        authoriys.add("user:update");
        authoriys.add("user:delete");
        authoriys.add("user:find");

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();        
        authorizationInfo.addRoles(roles);
        authorizationInfo.addStringPermissions(authoriys);
        return authorizationInfo;
    }
    
	//认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        System.out.println("执行认证操作");
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;

        String username = token.getUsername();
        String userpwd = new String(token.getPassword());

        if ("jx".equals(username) && "123456".equals(userpwd)){
            SimpleAuthenticationInfo myshrio =
                    new SimpleAuthenticationInfo(username, userpwd, "myRealm");//1.安全数据  2.用户密码 3.当前realm
            
            return  myshrio;

        }else{
            System.out.println("账号密码错误");
            throw new RuntimeException("账号密码错误");
        }
    }
}

3.测试

   @Test
    public void show(){

        //创建工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shrio_test_03.ini");
        //获取对象
        SecurityManager instance = factory.getInstance();
        //绑定当前对象到运行环境
       SecurityUtils.setSecurityManager(instance);
        //当前环境获取subject
        Subject subject = SecurityUtils.getSubject();
        //用户
       String username = "jx";
       String userpwd = "123456";
        //获取到令牌
        UsernamePasswordToken token = new UsernamePasswordToken(username, userpwd);
        //登录验证
         subject.login(token);

        System.out.println(subject.isAuthenticated());
        System.out.println(subject.hasRole("role1")); //true
        System.out.println(subject.hasRole("role2")); //true
        System.out.println(subject.isPermitted("user:save")); //true
        System.out.println(subject.isPermitted("user:find")); //true
    }

3.编码、散列算法

3.1编码与解码

Shiro提供了base64和16进制字符串编码/解码的API支持,方便一些编码解码操作。

Shiro内部的一些数据的【存储/表示】都使用了base64和16进制字符串

3.2散列算法

散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据,常见的散列算法如MD5、SHA等。一般进行散列时最好提供一个salt(盐),比如加密密码“admin”,产生的散列值是“21232f297a57a5a743894a0e4a801fc3”,可以到一些md5解密网站很容易的通过散列值得到密码“admin”,即如果直接对密码进行散列相对来说破解更容易,此时我们可以加一些只有系统知道的干扰数据,如salt(即盐);这样散列的对象是“密码+salt”,这样生成的散列值相对来说更难破解。

shiro支持的散列算法:

Md2Hash、Md5Hash、Sha1Hash、Sha256Hash、Sha384Hash、Sha512Hash

案例

1.构建编码,解码类

package com.ape.code;

import org.apache.shiro.codec.Base64;
import org.apache.shiro.codec.Hex;

/**
 * @author jx
 * @version 1.0
 * @since 2023/11/6
 **/
public class GetCode {

    // 编码
    public static String Hexencode(byte[] bytes){
        return new String(Hex.encode(bytes));
    }

    // 解码
    public static byte[] Hexdecode(String code){
        return Hex.decode(code);
    }

    // 编码
    public static String Base64encode(byte[] bytes){
        return new String(Base64.encode(bytes));
    }

    // 解码
    public static byte[] Base64decode(String code){
        return Base64.decode(code);
    }
}

2.测试类

//Hex
@Test
public void show1(){

    String code = "123456789";
    String hexencode = GetCode.Hexencode(code.getBytes());
    System.out.println(hexencode);
    byte[] hexdecode = GetCode.Hexdecode(hexencode);
    System.out.println(new String(hexdecode));
}

//Base64
@Test
public void show2(){
    String code = "apesource";
    String hexencode = GetCode.Base64encode(code.getBytes());
    System.out.println(hexencode);
    byte[] hexdecode = GetCode.Base64decode(hexencode);
    System.out.println(new String(hexdecode));
}

4.身份授权

4.1授权流程

1、首先调用Subject.isPermitted/hasRole接口,其会委托给SecurityManager。

2、SecurityManager接着会委托给内部组件Authorizer;

3、Authorizer再将其请求委托给我们的Realm去做;Realm才是真正干活的;

4、Realm将用户请求的参数封装成权限对象。再从我们重写的doGetAuthorizationInfo方法中获取从数据库中查询到的权限集合。

5、Realm将用户传入的权限对象,与从数据库中查出来的权限对象,进行一一对比。如果用户传入的权限对象在从数据库中查出来的权限对象中,则返回true,否则返回false。

进行授权操作的前提:用户必须通过认证。

5.Shiro默认过滤器

Shiro内置了很多默认的过滤器,比如身份验证、授权等相关的。默认过滤器可以参考org.apache.shiro.web.filter.mgt.DefaultFilter中的枚举过滤器
在这里插入图片描述

5.1认证相关
过滤器过滤器类说明默认
authcFormAuthenticationFilter基于表单的过滤器;如“/**=authc”,如果没有登录会跳到相应的登录
logoutLogoutFilter退出过滤器,主要属性:redirectUrl:退出成功后重定向的地址,如“/logout=logout”/
anonAnonymousFilter匿名过滤器,即不需要登录即可访问;一般用于静态资源过滤;示例“/static/**=anon”
userUserFilter用户拦截器,用户已经身份验证/记住我登录的都可;示例“/**=user”
authcBasicBasicHttpAuthenticationFilterBasic HTTP身份验证拦截器,主要属性: applicationName:弹出登录框显示的信息(application);
5.2授权相关
过滤器过滤器类说明
rolesRolesAuthorizationFilter角色授权拦截器,验证用户是否拥有所有角色; 主要属性: loginUrl:登录页面地址(/login.jsp);unauthorizedUrl:未授权后重定向的地址;示例“/admin/**=roles[admin]”
permsPermissionsAuthorizationFilter权限授权拦截器,验证用户是否拥有所有权限;属性和roles一样;示例“/user/**=perms[“user:create”]”
portPortFilter端口拦截器,主要属性:port(80):可以通过的端口;示例“/test= port[80]”,如果用户访问该页面是非80,将自动将请求端口改为80并重定向到该80端口,其他路径/参数等都一样
restHttpMethodPermissionFilterrest风格拦截器,自动根据请求方法构建权限字符串(GET=read, POST=create,PUT=update,DELETE=delete,HEAD=read,TRACE=read,OPTIONS=read, MKCOL=create)构建权限字符串;示例“/users=rest[user]”,会自动拼出“user:read,user:create,user:update,user:delete”权限字符串进行权限匹配(所有都得匹配,isPermittedAll);
sslSslFilterSSL拦截器,只有请求协议是https才能通过;否则自动跳转会https端口(443);其他和port拦截器一样;
文章来源:https://blog.csdn.net/ji_xin0721/article/details/135694838
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。