shiro基础教程

shiro作为一个安全框架,可以很好的在javaee项目中使用,他可以不依赖于spring单独使用。也可以和spring框架一起使用。现在的springboot开发中也越来越多的使用shiro来做安全验证。

shiro框架的三大核心组件:SecurityManager,Realm,Subject。三者构成了安全框架的主要组成部分。

SecurityManager:管理shiro内部组件,负责管理Subject,Session,Cache,验证,授权。

Realm:为shiro验证用户是否存在或者是否有相关权限提供数据支持。

Subject:主体,当前操作的用户。

shiro入门,一般从最简单的登录验证开始。我们构建maven工程,引入依赖:

<dependencies>
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.11</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>commons-logging</groupId>
  <artifactId>commons-logging</artifactId>
  <version>1.1.3</version>
</dependency>
<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-core</artifactId>
  <version>1.4.0</version>
</dependency>
<dependency>
  <groupId>com.zaxxer</groupId>
  <artifactId>HikariCP</artifactId>
  <version>2.7.9</version>
</dependency>
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.46</version>
</dependency>
</dependencies>

从最简单的iniRealm开始,我们准备一个shiro-user.ini 的配置文件,内容如下:

[users]
admin=123456,admin
[roles]
admin=*

直接利用单元测试测试登录:

@Test
public void initTest() {
	Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-user.ini");
	SecurityManager securityManager = factory.getInstance();
	SecurityUtils.setSecurityManager(securityManager);
	Subject subject = SecurityUtils.getSubject();
	UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");
	try {
		subject.login(token);
	} catch (Exception e) {
		e.printStackTrace();
	}
	if(subject.isAuthenticated()) {
		System.out.println(subject.getPrincipal().toString()+" login successfully.");
	}
}

单元测试成功,打印:admin login successfully.

这个示例的过程大致是先创建SecurityManager,然后创建Subject,最后登录。 这个示例的数据来源于ini配置文件,看不出来自Realm。下面开始另一个示例,构建一个SimpleAccountRealm:

SimpleAccountRealm realm = new SimpleAccountRealm();
@Before
public void before() {
	realm.addAccount("admin", "123456");
}

@Test
public void simpleRealmTest() {
	DefaultSecurityManager securityManager = new DefaultSecurityManager();
	securityManager.setRealm(realm);
	SecurityUtils.setSecurityManager(securityManager);
	Subject subject = SecurityUtils.getSubject();
	UsernamePasswordToken token = new UsernamePasswordToken("admin","123456");
	try {
		subject.login(token);
	} catch (Exception e) {
		e.printStackTrace();
	}	
	if(subject.isAuthenticated()) {
		System.out.println(subject.getPrincipal().toString()+" login successfully.");
	}
}

同样测试会成功。打印和第一个示例一样的信息。这个示例很好的说明了Realm为shiro提供了验证用户和用户是否拥有权限数据支持。我们也可以自定义Realm,让他实现类似的功能。

CustomRealm.java

package com.xxx.shirodemo.realm;
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;
public class CustomRealm extends AuthorizingRealm {

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		return info;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		String username = (String) token.getPrincipal();
		if(!"admin".equals(username)) {
			return null;
		}
		SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,"123456",getName());
		return info;
	}

}

单元测试方法:

@Test
public void customRealmTest() {
	DefaultSecurityManager securityManager = new DefaultSecurityManager();
	CustomRealm realm = new CustomRealm();
	securityManager.setRealm(realm);
	SecurityUtils.setSecurityManager(securityManager);
	Subject subject = SecurityUtils.getSubject();
	UsernamePasswordToken token = new UsernamePasswordToken("admin","123456");
	try {
		subject.login(token);
	} catch (Exception e) {
		e.printStackTrace();
	}	
	if(subject.isAuthenticated()) {
		System.out.println(subject.getPrincipal().toString()+" login successfully.");
	}
}

这种方式和第二种方式也类似,只不过使用了自定义的Realm。数据还是来源于内存设置,我们可以利用JdbcRealm来实现数据来源于数据库。这里要用到HikariCP数据源。还需要准备一个mysql数据库webapp,然后准备一张表users至少包含username,password两个字段。

@Test
public void jdbcRealmTest() {
	String jdbcUrl = "jdbc:mysql:///webapp?useUnicode=true&useSSL=false";
	String driverClassName = "com.mysql.jdbc.Driver";
	Properties properties = new Properties();
	String username = "hadoop";
	String password="hadoop";
	DriverDataSource dataSource = new DriverDataSource(jdbcUrl, driverClassName, properties, username, password);
	JdbcRealm realm = new JdbcRealm();
	realm.setDataSource(dataSource);
	CredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher("md5");
	realm.setCredentialsMatcher(credentialsMatcher);
	
	DefaultSecurityManager securityManager = new DefaultSecurityManager();
	securityManager.setRealm(realm);
	SecurityUtils.setSecurityManager(securityManager);
	Subject subject = SecurityUtils.getSubject();
	UsernamePasswordToken token = new UsernamePasswordToken("admin","123456");
	try {
		subject.login(token);
	} catch (Exception e) {
		e.printStackTrace();
	}
	if(subject.isAuthenticated()) {
		System.out.println(subject.getPrincipal().toString()+" login successfully.");
	}
}

这里我的数据库中的用户密码经过了md5加密:

mysql> select * from users;
+----+----------+----------------------------------+
| id | username | password                         |
+----+----------+----------------------------------+
|  1 | admin    | e10adc3949ba59abbe56e057f20f883e |
+----+----------+----------------------------------+
1 row in set

JdbcRealm需要设置credentialsMatcher,其中credentialsMatcher的加密方法采用MD5。这样整个示例就可以测试通过了。 

 几个单元测试下来,我们基本搞清楚了shiro登录验证的基本流程,创建securityManager->创建Subject->登录验证login。这里面需要我们注意的就是如何构建securityManager,是否使用自定义的Realm,用户密码是否加密等。

如果用户名不存在,报错:

org.apache.shiro.authc.UnknownAccountException: Realm [com.xxx.shirodemo.realm.CustomRealm@5577140b] was unable to find account data for the submitted AuthenticationToken [org.apache.shiro.authc.UsernamePasswordToken - admin1, rememberMe=false]

如果密码不正确,报错:

org.apache.shiro.authc.IncorrectCredentialsException: Submitted credentials for token [org.apache.shiro.authc.UsernamePasswordToken - admin, rememberMe=false] did not match the expected credentials.

在web项目中,我们可以根据不同的异常类型,返回页面不同的提示语,用户名不存在,密码错误等。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luffy5459

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值