shiro权限框架

一、概述

Apache Shiro 是一个强大易用的 Java 安全框架,提供了认证、授权、加密和会话管理等功能,对于任何一个应用程序,Shiro 都可以提供全面的安全管理服务。并且相对于其他安全框架,Shiro 要简单的多。

什么是认证?

认证就是用户身份识别,常被称为用户“登录”,判断用户是否登陆,如果未登陆则拦截其请求。

什么是授权?

授权即对用户的操作进行控制。当用户访问某些资源时,系统先判断其身份是否有权限访问相应的资源,如果有则允许继续访问;如果没有则进行拦截,不让其访问该资源。

二、Shiro的工作方式

如果从用户角度来看,Shiro框架的工作方式如下图所示:
在这里插入图片描述
从上图可以看到,应用程序与Subject(主体)进行交互。Subject代表当前登录用户,它保存了当前登录用户的信息。应用程序通过Subject来进行认证和授权。而主体又委托给Security Manager(安全管理器)来完成相应工作。用户需要将Realm传给会话管理器,从而让会话管理器能够得到合法的用户,以及对用户的访问权限进行判断。

Shiro框架的内部结构如下图所示:
在这里插入图片描述
主体(Subject):主体可以是程序,也可以是一个对象。在Web应用中,一般使用当前登录用户作为主体。如果主体要访问系统,那么Shiro就会对主体进行认证、授权等工作;
安全管理器(SecurityManager):执行了主体的认证和授权工作;
认证器(Authenticator):负责执行认证操作;
授权器(Authorizer):负责执行授权操作;
会话管理器(SessionManager):Shiro接管了Web中的Session。Shiro对Session的管理工作就是通过该管理器进行;
领域(Realm):相当于数据源。通过该Realm存取认证、授权相关的数据;

三、SpringBoot整合Shiro的基本步骤

3.1 环境准备

在springboot项目中添加以下坐标:

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

然后创建一个配置类,用于配置ShiroFilterFactoryBean对象。

@Configuration
public class ShiroConfiguration {

	@Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        return shiroFilterFactoryBean;
    }

    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        return securityManager;
    }
	
}

3.2 身份认证

身份认证即在应用程序证明是不是本人。一般提供一些代表用户身份的信息来表明他就是他本人,如用户名和密码。

在 shiro 中,用户需要提供 principals (身份)和 credentials(证明)给 shiro,从而应用能验证用户身份。任何东西,如用户名、邮箱等都可以作为principals使用,只需要保证它们能够唯一标识该用户即可。一个主体可以有多个 principals,但只有一个 Primary principals。

3.2.1 实现认证的基本流程

在这里插入图片描述
第一步:搜集用户身份信息,如用户名和密码;
第二步:调用Subject对象的login方法进行登录。如果登录失败,该方法会抛出AuthenticationException异常;

下面以用户登录为例,演示如何实现用户身份认证。

@RequestMapping(path="/login.do", produces="application/json;charset=utf-8")
@ResponseBody
public Map login(HttpServletRequest request, Emp emp) {
	//第一步:创建令牌
	UsernamePasswordToken token = new UsernamePasswordToken(
			emp.getUsername(), emp.getPwd());
	//第二步:获取Subject对象,该对象封装了一系列的操作
	Subject subject = SecurityUtils.getSubject();
	//第三步:执行认证
	try {
		subject.login(token);
		return ajaxReturn(true, "登录成功!");
	} catch (AuthenticationException e) {
		e.printStackTrace();
	}
	return ajaxReturn(false, "登录失败!");
}

3.2.2 自定义Realm

从上面登录方法看到,登陆时并不直接调用业务逻辑判断用户名密码是否正确,而是将这项工作交给了shiro去完成。那shiro是怎么知道你的用户名和密码是否正确呢? 当然shiro自己肯定不知道,它需要“打听一个人”,那就是Realm。其实真正实现登陆校验的是Realm ,而Shiro只是去调用Realm。

自定义Realm的基本步骤:

第一步:定义一个类,继承AuthorizingRealm,并重写doGetAuthenticationInfo方法;

@Override
protected AuthenticationInfo doGetAuthenticationInfo(
		AuthenticationToken arg0) throws AuthenticationException {
	//1.得到令牌
	UsernamePasswordToken token = (UsernamePasswordToken) arg0;
	//2.调用业务组件进行登录判断
	String password = new String(token.getPassword());
	User user = userService.findUsers(token.getUsername(), password);
	//3.判断用户是否为空,如果不为空代表登录成功
	if (user != null) {
		return new SimpleAuthenticationInfo(
				user, //priciple,使用当前登录用户对象
				password,  //credentials
				user.getName()); //realmName
	}
	//方法返回Null代表验证失败
	return null;
}

Shiro执行认证时会自动调用doGetAuthenticationInfo方法。

第二步:在配置类中配置该Realm。

@Bean
public UserRealm userRealm() {
	return new UserRealm();
}

@Bean
public SecurityManager securityManager() {
	DefaultSecurityManager securityManager = new DefaultWebSecurityManager();
	securityManager.setRealm(userRealm());
	return securityManager;
}

3.2.3 获取登录用户信息

Subject subject = SecurityUtils.getSubject();
User user = (User) subject.getPrincipal();

3.2.4 注销

SecurityUtils.getSubject().logout();

3.2.5 认证规则

Shiro过滤器与URL匹配规则都是定义在ShiroFilterFactoryBean对象中。Shiro是以过滤器的方式对访问规则进行控制,并内置了一组过滤器,例如:
anon:不认证也可以访问;
authc:必须认证后才可以访问;
perms:指定资源需要哪些权限才可以访问;

例如:

# 可以匿名使用
/adminjs/*=anon 

# 需要认证才能使用
/adminjs/user/*=authc

# 指定资源需要哪些权限才可以访问
/adminjs/user/*=perms[“权限名”]

URL匹配规则:

“?”:匹配一个字符,如”/admin?”,将匹配“ /admin1”、“/admin2”,但不匹配“/admin”;
“*”:匹配零个或多个字符串,如“/admin*”,将匹配“ /admin”、“/admin123”,但不匹配“/admin/1”
“**”:匹配路径中的零个或多个路径,如“/admin/**”,将匹配“/admin/a”、“/admin/a/b”

3.2.6 配置资源访问规则

@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    //配置安全管理器
    shiroFilterFactoryBean.setSecurityManager(securityManager); 
    //配置资源的访问规则
    Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
    filterChainDefinitionMap.put("/login.html", "anon");
    filterChainDefinitionMap.put("/adminjs/**", "anon");
    filterChainDefinitionMap.put("/easyui/**", "anon");
    filterChainDefinitionMap.put("/css/**", "anon");
    filterChainDefinitionMap.put("/images/**", "anon");
    filterChainDefinitionMap.put("/sys/login.do", "anon");
    filterChainDefinitionMap.put("/sys/getCookie.do", "anon");
    filterChainDefinitionMap.put("/**", "authc");
    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    //指定认证失败后跳转的页面
    shiroFilterFactoryBean.setLoginUrl("/login.html"); 
    return shiroFilterFactoryBean;
}

3.3 授权

3.3.1 授权流程

在这里插入图片描述
授权流程:
1)当调用 Subject.isPermitted方法时,shiro会委托给 SecurityManager,而 SecurityManager 接着会委托给 Authorizer进行授权相关工作。Authorizer 是真正的授权者,如果我们调用如 isPermitted方法,Authorizer 会通过 PermissionResolver 把字符串转换成相应的 Permission 实例。
2)在授权前,Authorizer会调用相应的 Realm 对象,并获取 Subject 相应的角色/权限,用于匹配传入的角色/权限。
3)Authorizer会判断Realm的角色/权限是否和传入的角色/权限相匹配。如果匹配则返回true,代表授权成功;否则返回false,代表授权失败。

3.3.2 授权实现

第一步:重写AuthorizingRealm对象的doGetAuthorizationInfo方法。

@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
	System.out.println("执行授权的方法...");
	//获取当前登录用户
	Emp emp = (Emp) arg0.getPrimaryPrincipal();
	//获取用户所拥有的菜单权限
	List<Menu> menus = menuBus.findMenus(emp.getUuid());
	//该对象保存了当前登录用户的权限信息
	SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
	for (Menu menu : menus) {
		//设置用户所具有的权限信息
		info.addStringPermission(menu.getMenuname());
	}
	return info;
}

第二步:定义规则;

@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    //配置安全管理器
    shiroFilterFactoryBean.setSecurityManager(securityManager); 
    //配置资源的访问规则
    Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
    filterChainDefinitionMap.put("/login.html", "anon");
    filterChainDefinitionMap.put("/adminjs/**", "anon");
    filterChainDefinitionMap.put("/easyui/**", "anon");
    filterChainDefinitionMap.put("/css/**", "anon");
    filterChainDefinitionMap.put("/images/**", "anon");
    filterChainDefinitionMap.put("/sys/login.do", "anon");
    
    // 权限规则
    List<Menu> menus = menuService.findAll();
    for (Menu menu : menus) {
		filterChainDefinitionMap.put(menu.getUrl(), "perms['" + menu.getName() + "']");
	}
    filterChainDefinitionMap.put("/**", "authc");shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    //指定认证失败后跳转的页面
    shiroFilterFactoryBean.setLoginUrl("/login.html"); 
    return shiroFilterFactoryBean;
}

上面代码第15~20行定义权限规则,只有用户具有相对应的权限后,才允许访问指定url的资源。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值