Shiro权限认证

   一、权限认证核心要素

权限认证顾名思义,就是在应用系统中,控制谁能访问哪些资源。核心要素有仨:权限、角色、用户

权限:即操作资源的权利,如访问某个url,对某个模块数据进行增删改查

角色:权限的集合,一种角色可以包含多种权限。例如操作员角色可查看系统账单、进行结账操作多种权限。

用户:也就是身份认证中提到的subject一角。

二、授权

shiro授权的方式通常有三种:

1、编程式授权:在代码中进行授权操作,可基于角色和权限两种方式。

2、注解式授权:使用注解对方法或类进行授权,标注该类可被哪些权限、角色所使用。

3、Jsp标签授权:shiro比较灵活的地方笔者觉得就是jsp标签授权,通过shiro的guest、user、principal等标签,可通过访问权限的不同,控制页面信息显示。免去了一大部分后台处理逻辑。好方便,好好用。后面会有详细介绍。

三、编程式授权实例

1、同样首先创建ini文件

[users]
java1234=123456,role1,role2
jack=123,role1

这是一个通过角色授权的方式,具体含义是指:用户名为java1234的用户享有role1,role2角色的权利,jack用户享有role1的权利。

2、java代码通过hasRole 和checkRole的方法可判断某用户是否具有role1、role2角色权利。

这里首先将一些shiro初始化、预处理的操作封装成一个util类

public class ShiroUtil {
	public static Subject login(String configFile,String userName,String password){
		// 读取配置文件,初始化SecurityManager工厂
		Factory<SecurityManager> factory=new IniSecurityManagerFactory(configFile);
		// 获取securityManager实例
		SecurityManager securityManager=factory.getInstance();
		// 把securityManager实例绑定到SecurityUtils
		SecurityUtils.setSecurityManager(securityManager);
		// 得到当前执行的用户
		Subject currentUser=SecurityUtils.getSubject();
		// 创建token令牌,用户名/密码
		UsernamePasswordToken token=new UsernamePasswordToken(userName, password);
		try{
			// 身份认证
			currentUser.login(token);
			System.out.println("身份认证成功!");
		}catch(AuthenticationException e){
			e.printStackTrace();
			System.out.println("身份认证失败!");
		}
		return currentUser;
	}
}

新建roleTest类,通过调用user的hasRole、checkRole方法判断用户权限。

public class RoleTest {

	@Test
	public void testHasRole() {
		Subject currentUser=ShiroUtil.login("classpath:shiro_role.ini", "java1234", "123456");
		// Subject currentUser=ShiroUtil.login("classpath:shiro_role.ini", "jack", "123");
		System.out.println(currentUser.hasRole("role1")?"有role1这个角色":"没有role1这个角色");
		boolean []results=currentUser.hasRoles(Arrays.asList("role1","role2","role3"));
		System.out.println(results[0]?"有role1这个角色":"没有role1这个角色");
		System.out.println(results[1]?"有role2这个角色":"没有role2这个角色");
		System.out.println(results[2]?"有role3这个角色":"没有role3这个角色");
		System.out.println(currentUser.hasAllRoles(Arrays.asList("role1","role2"))?"role1,role2这两个角色都有":"role1,role2这个两个角色不全有");

		currentUser.logout();
	}

	@Test
	public void testCheckRole() {
		Subject currentUser=ShiroUtil.login("classpath:shiro_role.ini", "java1234", "123456");
		// Subject currentUser=ShiroUtil.login("classpath:shiro_role.ini", "jack", "123");
		currentUser.checkRole("role1");
		currentUser.checkRoles(Arrays.asList("role1","role2"));
		currentUser.checkRoles("role1","role2","role3");

		currentUser.logout();
	}
}

通过权限permission的权限验证方式如下:

[users]
java1234=123456,role1,role2
jack=123,role1
[roles]
role1=user:select
role2=user:add,user:update,user:delete

这里就补充了role1、role2用户具体具有哪些操作权,role1可进行select操作,同理,role2可进行增删改操作。同样调用user关于permission认证的方法,可对用户具体操作权限进行认证。

public class PermissionTest {

	@Test
	public void testIsPermitted() {
		Subject currentUser=ShiroUtil.login("classpath:shiro_permission.ini", "java1234", "123456");
		// Subject currentUser=ShiroUtil.login("classpath:shiro_permission.ini", "jack", "123");
		System.out.println(currentUser.isPermitted("user:select")?"有user:select这个权限":"没有user:select这个权限");
		System.out.println(currentUser.isPermitted("user:update")?"有user:update这个权限":"没有user:update这个权限");
		boolean results[]=currentUser.isPermitted("user:select","user:update","user:delete");
		System.out.println(results[0]?"有user:select这个权限":"没有user:select这个权限");
		System.out.println(results[1]?"有user:update这个权限":"没有user:update这个权限");
		System.out.println(results[2]?"有user:delete这个权限":"没有user:delete这个权限");
		System.out.println(currentUser.isPermittedAll("user:select","user:update")?"有user:select,update这两个权限":"user:select,update这两个权限不全有");

		currentUser.logout();
	}

	@Test
	public void testCheckPermitted() {
		Subject currentUser=ShiroUtil.login("classpath:shiro_permission.ini", "java1234", "123456");
		// Subject currentUser=ShiroUtil.login("classpath:shiro_permission.ini", "jack", "123");
		currentUser.checkPermission("user:select");
		currentUser.checkPermissions("user:select","user:update","user:delete");
		currentUser.logout();
	}
}

  四、shiro与web集成进行权限认证

下面介绍在java
web程序中使用 Shiro进行权限认证。

  1. 首先也是添加shiro相关jar包:shiro-web、shiro-core;commons-logging、slf4j-api、log4j;jstl、javax.servlet.jsp-api、javax.servlet-api
  2. 在web.XML中添加shiroFilter过滤器,并初始化创建的shiro.ini配置文件。

  <listener>
	    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
  </listener>

	<!-- 添加shiro支持 -->
	<filter>
	    <filter-name>ShiroFilter</filter-name>
	    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
	</filter>

	<filter-mapping>
	    <filter-name>ShiroFilter</filter-name>
	    <url-pattern>/*</url-pattern>
	</filter-mapping>
	<!--省略loginServlet 和adminServlet配置ps.login 针对所有的/login请求,admin针对/admin-->

shiro.ini文件

[main]
authc.loginUrl=/login
roles.unauthorizedUrl=/unauthorized.jsp
perms.unauthorizedUrl=/unauthorized.jsp
[users]
java1234=123456,admin
jack=123,teacher
marry=234
json=345
[roles]
admin=user:*
teacher=student:*
[urls]
/login=anon
/admin=authc
/student=roles[teacher]
/teacher=perms["user:create"]

3.创建login和adminservlet,分别用于直接登陆转发到login.jsp,和admin登录进行身份验证,转发到succeess.jsp和error.jsp

public class LoginServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("login doget");
		req.getRequestDispatcher("login.jsp").forward(req, resp);
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("login dopost");
		String userName=req.getParameter("userName");
		String password=req.getParameter("password");
		Subject subject=SecurityUtils.getSubject();
		UsernamePasswordToken token=new UsernamePasswordToken(userName, password);
		try{
			subject.login(token);
			resp.sendRedirect("success.jsp");
		}catch(Exception e){
			e.printStackTrace();
			req.setAttribute("errorInfo", "用户名或者密码错误");
			req.getRequestDispatcher("login.jsp").forward(req, resp);
		}
	}
}

4.配置数据源-这里介绍两种reaml:Text
Reaml和自定义JDBC reaml 。

Text Reaml 配置详情与访问流程

text Reaml配置整合到Shiro.ini文件中,具体配置了四个用户,java1234拥有admin角色权限,jack拥有teacher角色权限;角色admin可对user进行任意crud操作,teacher可对student进行crud操作;访问的urls,请求/login地址时,这里的anon是指游客身份,不需要进行任何身份认证;请求/admin地址时,需要进行身份认证,进行filter过滤后,跳转到【main】中进行了配置为/login
(jsp页面),同样,role和perms的权限认证页设置为unauthorized.jsp;

上面ini配置达到的效果就是:当请求访问localhost:8080/shiro/login 时直接跳到hello页面,无需进行身份验证。当访问localhost:8080/shiro/admin时,先转发到login.jps进行身份验证,进入adminServlet,验证结束后转发到error或succeess页面。再次访问admin地址时,由于第一次访问记录了用户登录信息,故无需在登陆直接跳转到success页面。而访问localhost:8080/shiro/student时,login信息如果使用json(没有任何角色权限的用户),则因为该用户权限不足(因为配置中访问student需要teacher角色)直接跳转到无权限访问页面。这就是使用
textReaml进行身份验证和权限验证的配置。

自定义 JDBC Reaml的配置与访问流程

由于text Reaml的信息毕竟有限,配置也相对比较麻烦,所以一般应用程序使用的都是自定义reaml,此处创建一个自定义JDBC readml并演示reaml与java程序结合的流程。

由于需要创建数据库(创建用户、角色、权限三张表,依次主外键关联),然后首先引入数据库驱动jar包;在shiro,ini文件中指定当前securityManager使用的验证策略是自定义jdbcReaml。

[main]
authc.loginUrl=/login
roles.unauthorizedUrl=/unauthorized.jsp
perms.unauthorizedUrl=/unauthorized.jsp
myRealm=com.java.realm.MyRealm
securityManager.realms=$myRealm
[urls]
/login=anon
/admin*=authc
/student=roles[teacher]
/teacher=perms["user:create"]

最后创建数据库连接Util类和myReaml类调用底层数据查询dao即可。

/**
 * 数据库工具类
 * @author
 */
public class DbUtil {
	public Connection getCon() throws Exception{
		Class.forName("com.mysql.jdbc.Driver");
		Connection con=DriverManager.getConnection("jdbc:mysql://localhost:3306/db_shiro", "root", "123456");
		return con;
	}
	public void closeCon(Connection con)throws Exception{
		if(con!=null){
			con.close();
		}
	}
	public static void main(String[] args) {
		DbUtil dbUtil=new DbUtil();
		try {
			dbUtil.getCon();
			System.out.println("数据库连接成功");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("数据库连接失败");
		}
	}
}

MyReaml类:继承shiro
AuthorizingReaml类,重写身份验证和权限验证两个方法。(这里也就解释了为什么访问student地址时,并未配置需要先登录,程序却自动跳转到登录面。因为底层封装了默认请求都先进行身份认证的方法。)

public class MyRealm extends AuthorizingRealm{
	private UserDao userDao=new UserDao();
	private DbUtil dbUtil=new DbUtil();
	/**
	 * 为当前登录的用户授予角色和权限
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		String userName=(String)principals.getPrimaryPrincipal();
		SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
		Connection con=null;
		try{
			con=dbUtil.getCon();
			authorizationInfo.setRoles(userDao.getRoles(con,userName));
			authorizationInfo.setStringPermissions(userDao.getPermissions(con,userName));
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			try {
				dbUtil.closeCon(con);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return authorizationInfo;
	}
	/**
	 * 验证当前登录的用户
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		String userName=(String)token.getPrincipal();
		Connection con=null;
		try{
			con=dbUtil.getCon();
			User user=userDao.getByUserName(con, userName);
			if(user!=null){
				AuthenticationInfo authcInfo=new SimpleAuthenticationInfo(user.getUserName(),user.getPassword(),"xx");
				return authcInfo;
			}else{
				return null;
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			try {
				dbUtil.closeCon(con);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return null;
	}

}

这两个方法分别封装了一个身份信息实体类AuthenticationInfo 和AuthorizetionInfo返回。

首先获取用户信息,根据用户名查询数据库中的用户、权限等其他信息验证即可。整体流程是当浏览器访问例如:localhost:8080/shiro/admin 地址时,先调用loginServlet,在执行user.login方法时,进入自定义MyReaml类,获取用户信息,进行身份验证。



时间: 2024-10-13 18:35:59

Shiro权限认证的相关文章

shiro 权限认证的原理,个人的理解

1.对有没有访问权限的理解.  我们这里要对系统中的 角色组.角色.用户.功能 之间的关系要理清楚,http://blog.csdn.net/baicp3/article/details/45028013方便下面用户是否具有某一url的访问. 我们看shiro的配置文件,所以的请求都是需要用户登录的 因而用户 在登录成功时候,shiro已经把该用户是否有访问某一url的权限已经判断好了. 看下面简单的代码 @Override protected AuthorizationInfo doGetAu

springMVC集成shiro权限认证框架,登录之后退出登录出现登录不上的问题

有两种解决方式: 1.在web.xml文件配置一段欢迎页面: <welcome-file-list> <welcome-file>/index.do</welcome-file> </welcome-file-list> 2.在自定义表单过滤器MyFormAuthenticationFilter里,添加清除shiro 在sesion存储的上一次访问地址 shiroSavedReques 1 package cn.zj.logistic.shiro; 2 3

shiro权限认证Realm的四大用法

一.SimpleAccountRealm public class AuthenticationTest { SimpleAccountRealm sar=new SimpleAccountRealm(); @Before public void addUser() { sar.addAccount("mark", "123456","admin","user"); } @Test public void testAuthen

Spring Boot Shiro 权限管理 【转】

http://blog.csdn.net/catoop/article/details/50520958 主要用于备忘 本来是打算接着写关于数据库方面,集成MyBatis的,刚好赶上朋友问到Shiro权限管理,就先总结下发出来了. 使用Shiro之前用在spring MVC中,是通过XML文件进行配置. 既然现在在写Spring Boot的帖子,就将Shiro应用到Spring Boot中,我本地已经完成了SpringBoot使用Shiro的实例,将配置方法共享一下. 先简单介绍一下Shiro,

十、 Spring Boot Shiro 权限管理

使用Shiro之前用在spring MVC中,是通过XML文件进行配置. 将Shiro应用到Spring Boot中,本地已经完成了SpringBoot使用Shiro的实例,将配置方法共享一下. 先简单介绍一下Shiro,对于没有用过Shiro的朋友,也算是做个简介吧. Shiro是Apache下的一个开源项目,我们称之为Apache Shiro.它是一个很易用与Java项目的的安全框架,提供了认证.授权.加密.会话管理,与 Spring Security 一样都是做一个权限的安全框架,但是与S

Shiro身份认证、盐加密

目的: Shiro认证 盐加密工具类 Shiro认证 1.导入pom依赖 <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.apache.s

Shiro权限控制框架入门1:Shiro的认证流程以及基本概念介绍

前言:我在最开始学习Shiro这个框架时,在网上搜索到的一个介绍比较全面的教程是:<跟我学Shiro>系列教程.但是在我看了他写的前几篇文章后,我发现虽然他在这个系列教程中把shiro的一些特性介绍地非常全面详细,但是整个教程的叙述方式还是有很大缺陷的.文章与文章之间并没有很好地串联起来,每篇文章介绍的东西都过于分散了,如果是对shiro完全不了解的新手来看的话完全是一场噩梦.就像一个网友评价的这样: 看了看这个教程,看完之后都想放弃shiro了,完全看不懂,后来百度了很多别的资料才理解了sh

shiro中基于注解实现的权限认证过程

授权即访问控制,它将判断用户在应用程序中对资源是否拥有相应的访问权限. 如,判断一个用户有查看页面的权限,编辑数据的权限,拥有某一按钮的权限等等. 一.用户权限模型 为实现一个较为灵活的用户权限数据模型,通常把用户信息单独用一个实体表示,用户权限信息用两个实体表示. 用户信息用 LoginAccount 表示,最简单的用户信息可能只包含用户名 loginName 及密码 password 两个属性.实际应用中可能会包含用户是否被禁用,用户信息是否过期等信息. 用户权限信息用 Role 与 Per

【Shiro】Apache Shiro架构之权限认证(Authorization)

上一篇博文总结了一下Shiro中的身份认证,本文主要来总结一下Shiro中的权限认证(Authorization)功能,即授权.如下: 本文参考自Apache Shiro的官方文档:http://shiro.apache.org/authorization.html. 本文遵循以下流程:先介绍Shiro中的权限认证,再通过一个简单的实例来具体说明一下API的使用(基于maven). 1. 权限认证的核心要素 权限认证,也就是访问控制,即在应用中控制谁能访问哪些资源.在权限认证中,最核心的三个要素