shiro实战详解(2)
- 03 Shiro入门
- 1.身份认证
- 1.1基本流程
- 1.2案例
- 2.Realm
- 2.1Realm接口
- 2.2认证案例
- 2.3认证授权案例
- 3.编码、散列算法
- 3.1编码与解码
- 3.2散列算法
- 案例
- 4.身份授权
- 5.Shiro默认过滤器
- 5.1认证相关
- 5.2授权相关
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对象,并认证
@Testpublic void show1(){//1.创建工厂Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shrio_test_01.ini");//2.获取对象SecurityManager instance = factory.getInstance();//3.绑定当前对象到运行环境SecurityUtils.setSecurityManager(instance);//4.当前环境获取subjectSubject 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 {//授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {return null;}//认证@Overrideprotected 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.当前realmreturn 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类测试
@Testpublic void show(){//创建工厂Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shrio_test_02.ini");//获取对象SecurityManager instance = factory.getInstance();//绑定当前对象到运行环境SecurityUtils.setSecurityManager(instance);//当前环境获取subjectSubject 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")); //trueSystem.out.println(subject.hasRole("role2")); //trueSystem.out.println(subject.isPermitted("user:save")); //trueSystem.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 {//授权@Overrideprotected 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;}//认证@Overrideprotected 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.当前realmreturn myshrio;}else{System.out.println("账号密码错误");throw new RuntimeException("账号密码错误");}}
}
3.测试
@Testpublic void show(){//创建工厂Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shrio_test_03.ini");//获取对象SecurityManager instance = factory.getInstance();//绑定当前对象到运行环境SecurityUtils.setSecurityManager(instance);//当前环境获取subjectSubject 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")); //trueSystem.out.println(subject.hasRole("role2")); //trueSystem.out.println(subject.isPermitted("user:save")); //trueSystem.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认证相关
过滤器 | 过滤器类 | 说明 | 默认 |
---|---|---|---|
authc | FormAuthenticationFilter | 基于表单的过滤器;如“/**=authc”,如果没有登录会跳到相应的登录 | 无 |
logout | LogoutFilter | 退出过滤器,主要属性:redirectUrl:退出成功后重定向的地址,如“/logout=logout” | / |
anon | AnonymousFilter | 匿名过滤器,即不需要登录即可访问;一般用于静态资源过滤;示例“/static/**=anon” | 无 |
user | UserFilter | 用户拦截器,用户已经身份验证/记住我登录的都可;示例“/**=user” | 无 |
authcBasic | BasicHttpAuthenticationFilter | Basic HTTP身份验证拦截器,主要属性: applicationName:弹出登录框显示的信息(application); | 无 |
5.2授权相关
过滤器 | 过滤器类 | 说明 |
---|---|---|
roles | RolesAuthorizationFilter | 角色授权拦截器,验证用户是否拥有所有角色; 主要属性: loginUrl:登录页面地址(/login.jsp);unauthorizedUrl:未授权后重定向的地址;示例“/admin/**=roles[admin]” |
perms | PermissionsAuthorizationFilter | 权限授权拦截器,验证用户是否拥有所有权限;属性和roles一样;示例“/user/**=perms[“user:create”]” |
port | PortFilter | 端口拦截器,主要属性:port(80):可以通过的端口;示例“/test= port[80]”,如果用户访问该页面是非80,将自动将请求端口改为80并重定向到该80端口,其他路径/参数等都一样 |
rest | HttpMethodPermissionFilter | rest风格拦截器,自动根据请求方法构建权限字符串(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); |
ssl | SslFilter | SSL拦截器,只有请求协议是https才能通过;否则自动跳转会https端口(443);其他和port拦截器一样; |