这里写目录标题
Shiro有什么用
用于用户登录,权限拦截的使用
Shiro架构
什么是身份认证
Authentication,校验用户名和密码是否可以登录成功,可以登录则创建一个jsessionid给客户端
什么是授权
Authorization,将用户所有的访问权限查询出来,存到内存或库中
什么是会话管理
Session Management, 用户的会话管理,多数情况下是web session,jsessionid不要存储密码,权限等信息
什么是加密
数据加解密,比如密码加解密等,盐值加密等 (Cryptography)
Shiro认证流程
Subject
我们把用户或者程序称为主体(如用户,第三方服务,cron作业,爬虫),
主体去访问系统或者资源
SecurityManager
安全管理器,Subject的认证和授权都要在安全管理器下进行
Authenticator
认证器,主要负责Subject的认证
Realm
数据域,Shiro和安全数据的连接器,好比jdbc连接数据库; 通过realm获取认证授权相关信息
Authorizer
授权器,主要负责Subject的授权, 控制subject拥有的角色或者权限
Cryptography
加解密,Shiro的包含易于使用和理解的数据加解密方法,简化了很多复杂的api
Cache Manager
缓存管理器,比如认证或授权信息,通过缓存进行管理,提高性能
Shiro的使用
第一步:创建Relam实现类
创建一个或多个Relam类型的类(Relam接口有两个方法要实现)
Relam接口的实现类有两大作用(认证、授权)
1.它用于校验登录,校验是否可以登录,登录成功则返回一个授权对象 (认证)
2.它用于检查该用户是否有指定角色或权限 (授权)
Relam详情
shiro 自己定义了几个Relam,我们可以将用户、角色、权限等信息配置在文件中即可实现认证和授权,然而我们的权限信息要配置到库中,所以要自己定义一个或者多个Relam实现类,来实现认证和授权。
认证
认证会调用如下方法
认证会调用Relam接口实现类的 如下方法
//传入的token中存有 用户登录输入的用户名和密码
//根据传入的token中的用户名(唯一值)获得真正的密码
//根据用户名和真正的密码创建一个AuthenticationInfo对象返回
//返回后shiro会将 token中的信息和AuthenticationInfo对象中的信息进行比对,不同直接报错
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
认证流程
授权
授权会调用如下方法
授权会调用Relam接口实现类的 如下方法
//传入的PrincipalCollection 中存有用户名(唯一值)
//根据用户名从库中查找此用户的角色和权限,将角色和权限 放入到AuthorizationInfo 对象中
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals)
授权流程
第二步:创建SecurityManager实现类
SecurityManager实现类有什么用
SecurityManager用于用户的注销和登录
登录会返回一个Subject,Subject的一个成员变量是 SecurityManager
第三步:将SecurityManager和Relam进行绑定,同时通过SecurityManager获得对应的Subject
//自己定义的realm
CustomRealm customRealm = new CustomRealm();
//Shiro校验的核心对象
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//将Relam 和 defaultSecurityManager 进行绑定
defaultSecurityManager.setRealm(customRealm);
SecurityUtils.setSecurityManager(defaultSecurityManager);
//获取当前操作的主体
Subject subject = SecurityUtils.getSubject();
第四部:调用认证
//用户输入的账号密码
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack", "123");
//进行认证
subject.login(usernamePasswordToken);
System.out.println(" 认证结果:"+subject.isAuthenticated());
//拿到用户名
System.out.println(" getPrincipal=" + subject.getPrincipal());
第五步:进行授权
//进行授权
subject.checkRole("role1");
System.out.println("是否有对应的角色:"+subject.hasRole("role1"));
System.out.println("是否有对应的权限:"+subject.isPermitted("video:add"));
代码
依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
java
Relam对象
package com.atguigu.shiro.test;
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 java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* 自定义realm
*/
public class CustomRealm extends AuthorizingRealm {
private final Map<String,String> userInfoMap = new HashMap<>();
{
userInfoMap.put("jack","123");
userInfoMap.put("xdclass","456");
}
//role -> permission
private final Map<String,Set<String>> permissionMap = new HashMap<>();
{
Set<String> set1 = new HashSet<>();
Set<String> set2 = new HashSet<>();
set1.add("video:find");
set1.add("video:buy");
set2.add("video:add");
set2.add("video:delete");
permissionMap.put("jack",set1);
permissionMap.put("xdclass",set2);
}
//user -> role
private final Map<String,Set<String>> roleMap = new HashMap<>();
{
Set<String> set1 = new HashSet<>();
Set<String> set2 = new HashSet<>();
set1.add("role1");
set1.add("role2");
set2.add("root");
roleMap.put("jack",set1);
roleMap.put("xdclass",set2);
}
//进行权限校验的时候会调用
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("权限 doGetAuthorizationInfo");
String name = (String)principals.getPrimaryPrincipal();
Set<String> permissions = getPermissionsByNameFromDB(name);
Set<String> roles = getRolesByNameFromDB(name);
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.setRoles(roles);
simpleAuthorizationInfo.setStringPermissions(permissions);
return simpleAuthorizationInfo;
}
//当用户登陆的时候会调用
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("认证 doGetAuthenticationInfo");
//从token获取身份信息,token代表用户输入的信息
String name = (String)token.getPrincipal();
//模拟从数据库中取密码
String pwd = getPwdByUserNameFromDB(name);
if( pwd == null || "".equals(pwd)){
return null;
}
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, pwd, this.getName());
return simpleAuthenticationInfo;
}
/**
* 模拟从数据库获取用户角色集合
* @param name
* @return
*/
private Set<String> getRolesByNameFromDB(String name) {
return roleMap.get(name);
}
/**
* 模拟从数据库获取权限集合
* @param name
* @return
*/
private Set<String> getPermissionsByNameFromDB(String name) {
return permissionMap.get(name);
}
private String getPwdByUserNameFromDB(String name) {
return userInfoMap.get(name);
}
}
调用类
package com.atguigu.shiro.test;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
public class Luck{
public void testAuthentication() {
//自己定义的realm
CustomRealm customRealm = new CustomRealm();
//Shiro校验的核心对象
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//将Relam 和 defaultSecurityManager 进行绑定
defaultSecurityManager.setRealm(customRealm);
SecurityUtils.setSecurityManager(defaultSecurityManager);
//获取当前操作的主体
Subject subject = SecurityUtils.getSubject();
//用户输入的账号密码
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack", "123");
subject.login(usernamePasswordToken);
//登录
System.out.println(" 认证结果:"+subject.isAuthenticated());
//拿到主体标示属性
System.out.println(" getPrincipal=" + subject.getPrincipal());
subject.checkRole("role1");
System.out.println("是否有对应的角色:"+subject.hasRole("role1"));
System.out.println("是否有对应的权限:"+subject.isPermitted("video:add"));
}
public static void main(String[] args) {
new Luck().testAuthentication();
}
}