概述
1、shiro工作方式
首先,我们从外部来看Shiro吧,即从应用程序角度的来观察如何使用Shiro完成工作。如下图:
可以看到:应用代码直接交互的对象是Subject,也就是说Shiro的对外API核心就是Subject;其每个API的含义:
Subject:主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;即一个抽象概念;所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者;
SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器;
Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。
也就是说对于我们而言,最简单的一个Shiro应用:
1、应用代码通过Subject来进行认证和授权,而Subject又委托给SecurityManager;
2、我们需要给Shiro的SecurityManager注入Realm,从而让SecurityManager能得到合法的用户及其权限进行判断。
从以上也可以看出,Shiro不提供维护用户/权限,而是通过Realm让开发人员自己注入。
2、shiro
认证:
1、收集用户身份/凭证AuthenticationToken,即如用户名/密码;
2、SecurityUtils.getSubject()获取subject后,调用Subject.login进行登录,如果失败将得到相应的AuthenticationException异常,根据异常提示用户错误信息;否则登录成功;
3、最后调用Subject.logout进行退出操作。
4、前提,(1)配置好SecurityManager并设置给SubjectUtils;(2)reaml安全数据源配置
身份认证流程:
流程如下:
1、首先调用Subject.login(token)进行登录,其会自动委托给Security Manager,调用之前必须通过SecurityUtils. setSecurityManager()设置;
2、SecurityManager负责真正的身份验证逻辑;它会委托给Authenticator进行身份验证;
3、Authenticator才是真正的身份验证者,Shiro API中核心的身份认证入口点,此处可以自定义插入自己的实现;
4、Authenticator可能会委托给相应的AuthenticationStrategy进行多Realm身份验证,默认ModularRealmAuthenticator会调用AuthenticationStrategy进行多Realm身份验证;
5、Authenticator会把相应的token传入Realm,从Realm获取身份验证信息,如果没有返回/抛出异常表示身份验证失败了。此处可以配置多个Realm,将按照相应的顺序及策略进行访问。
realm:DataSource—ca
org.apache.shiro.realm.Realm接口如下:
String getName(); //返回一个唯一的Realm名字
boolean supports(AuthenticationToken token); //判断此Realm是否支持此Token
AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException; //根据Token获取认证信息
getAuthenticationInfo()的作用是:(1)判断是否是安全数据,不是抛异常(2)new simpleAuthenticationInfo并return [AuthenticatingRealm中封装了方法优先 从缓存中获取 authenticationInfo]
[注:tx框架中在获取user中完成(1),并override了获取authenticationInfo]
4、SecurityManager:
【获取1】
//1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
Factory<org.apache.shiro.mgt.SecurityManager> factory =
new IniSecurityManagerFactory("classpath:shiro.ini");
//2、得到SecurityManager实例 并绑定给SecurityUtils
org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
【获取2】
/**
* 安全管理器
*
* @return
*/
@Bean("securityManager")
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(shiroRealm());
securityManager.setSessionManager(sessionManager());
securityManager.setCacheManager(cacheManager());
return securityManager;
}
//advisor.setSecurityManager(securityManager());
SecurityManager(类DefaultWebSecurityManager)
(1)为其设置authenticator 、authorizer 、Realm 、SessionManager、CacheManager
(2)将 SecurityManager 设置到 SecurityUtils 方便全局使用
Authenticator & AuthenticationStratrgy
shiro默认提供三种认证策略
3、shiro—授权
授权方式
Shiro支持三种方式的授权:
编程式:通过写if/else授权代码块完成:
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole(“admin”)) {
//有权限
} else {
//无权限
}
注解式:通过在执行的Java方法上放置相应的注解完成:
@RequiresRoles("admin")
public void hello() {
//有权限
}
没有权限将抛出相应的异常;
JSP/GSP标签:在JSP/GSP页面通过相应的标签完成:
<shiro:hasRole name="admin">
<!— 有权限 —>
</shiro:hasRole>
判断权限
Shiro提供了
isPermitted和isPermittedAll用于判断用户是否拥有某个权限或所有权限。
checkPermission("") checkPermissions("") 无权限时抛异常
授权流程
1、首先调用Subject.isPermitted*/hasRole*接口,其会委托给SecurityManager,而SecurityManager接着会委托给Authorizer;
2、Authorizer是真正的授权者,如果我们调用如isPermitted(“user:view”),其首先会通过PermissionResolver把字符串转换成相应的Permission实例;
3、在进行授权之前,其会调用相应的Realm获取Subject相应的角色/权限用于匹配传入的角色/权限;
4、Authorizer会判断Realm的角色/权限是否和传入的匹配,如果有多个Realm,会委托给ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted*/hasRole*会返回true,否则返回false表示授权失败。
[3]
/**
* 权限
*
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("za方法");
String username = (String) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setStringPermissions(adminService.permissions(username));
return authorizationInfo;
}
ModularRealmAuthorizer进行多Realm匹配流程:
1、首先检查相应的Realm是否实现了实现了Authorizer;
2、如果实现了Authorizer,那么接着调用其相应的isPermitted*/hasRole*接口进行匹配;
3、如果有一个Realm匹配那么将返回true,否则返回false。
如果Realm进行授权的话,应该继承AuthorizingRealm,其流程是:
1.1、如果调用hasRole*,则直接获取AuthorizationInfo.getRoles()与传入的角色比较即可;
1.2、首先如果调用如isPermitted(“user:view”),首先通过PermissionResolver将权限字符串转换成相应的Permission实例,默认使用WildcardPermissionResolver,即转换为通配符的WildcardPermission;
2、通过AuthorizationInfo.getObjectPermissions()得到Permission实例集合;通过AuthorizationInfo. getStringPermissions()得到字符串集合并通过PermissionResolver解析为Permission实例;然后获取用户的角色,并通过RolePermissionResolver解析角色对应的权限集合(默认没有实现,可以自己提供);
3、接着调用Permission. implies(Permission p)逐个与传入的权限比较,如果有匹配的则返回true,否则false。
自定义realm:
public class RcRealm extends AuthorizingRealm {
@Autowired
private AdminService adminService;
/**
* 认证
* 获取身份验证信息
* @param token
* @return
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
System.out.println("ca方法");
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo
(token.getPrincipal(), token.getCredentials(), getName());
return simpleAuthenticationInfo;
}
/**
* 权限
* 根据用户身份 获取授权信息
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("za方法");
String username = (String) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setStringPermissions(adminService.permissions(username));
return authorizationInfo;
}
}
public class UserRealm extends AuthorizingRealm {
private UserService userService = new UserServiceImpl();
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String)principals.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setRoles(userService.findRoles(username));
authorizationInfo.setStringPermissions(userService.findPermissions(username));
return authorizationInfo;
}
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String)token.getPrincipal();
User user = userService.findByUsername(username);
if(user == null) {
throw new UnknownAccountException();//没找到帐号
}
if(Boolean.TRUE.equals(user.getLocked())) {
throw new LockedAccountException(); //帐号锁定
}
//交给 AuthenticatingRealm 使用 CredentialsMatcher 进行密码匹配,如果觉得人家 的不好可以在此判断或自定义实现
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
user.getUsername(), //用户名
user.getPassword(), //密码
ByteSource.Util.bytes(user.getCredentialsSalt()),//salt=username+salt
getName() //realm name
);
return authenticationInfo;
}
}
另外我们可以使用 JdbcRealm,需要做的操作如下:
1、执行 sql/ shiro-init-data.sql 插入相关的权限数据;
2、使用 shiro-jdbc-authorizer.ini 配置文件,需要设置 jdbcRealm.permissionsLookupEnabled 为 true 来开启权限查询。
5、加密
【base64】
String str = "hello";
String base64Encoded = Base64.encodeToString(str.getBytes());
String str2 = Base64.decodeToString(base64Encoded);
Assert.assertEquals(str, str2);
【16进制】
String str = "hello";
String base64Encoded = Hex.encodeToString(str.getBytes());
String str2 = new String(Hex.decode(base64Encoded.getBytes()));
Assert.assertEquals(str, str2);
【Md5】
String str = "hello";
String md5Encoded= DigestUtils.md5Hex(str);
String str = "hello";
String salt = "123";
String md5 = new Md5Hash(str, salt).toString();//还可以转换为 toBase64()/toHex()
【SHA】
String str = "hello";
String salt = "123";
String sha1 = new Sha256Hash(str, salt).toString();
【通用散列支持】
String str = "hello";
String salt = "123";
//内部使用 MessageDigest
String simpleHash = new SimpleHash("SHA-1", str, salt).toString();
[注]
类 CodecSupport,提供了 toBytes(str, "utf-8") / toString(bytes, "utf-8")用于在 byte 数组/String 之间转换
=====================================
Q2:
DigestUtils.md5Hex()如何加盐?底层实现
Q1:
官网用shiro(只认证无授权),光大用shiro(认证授权),其他不用shiro,各自原因?
最后
以上就是超帅吐司为你收集整理的跟我学shiro(开涛)阅读笔记1、shiro工作方式2、shiro3、shiro—授权5、加密的全部内容,希望文章能够帮你解决跟我学shiro(开涛)阅读笔记1、shiro工作方式2、shiro3、shiro—授权5、加密所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复