Spring之shiro使用教程

Shiro是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理等功能。谈及shiro必然少不了一张图和三个关键词语:Subject, SecurityManager 和 Realms。
在这里插入图片描述
简单来说可以总结为:

Subject:用户提交的请求
SecurityManager:shiro核心代码
Realms:shrio沟通数据库和缓存的一个中间桥梁(分为三类:iniRealm、jdbcRealm、自定义Realm)

  1. 一个简单的shiro程序步骤
        // 指定认证的数据
		SimpleAccountRealm accountRealm = new SimpleAccountRealm();
		// 模拟添加用户
		accountRealm.addAccount("xingdo", "123456","admin","user");
		// 构建SecurityManager对象
		DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
		defaultSecurityManager.setRealm(accountRealm);
		// 4.主体提交认证请求
		SecurityUtils.setSecurityManager(defaultSecurityManager);// 构建SecurityManager环境
		Subject subject = SecurityUtils.getSubject();

		UsernamePasswordToken token = new UsernamePasswordToken("xingdo", "123456");
		subject.login(token);//模拟登录
		System.out.println("是否执行了认证"+subject.isAuthenticated());
		
        //subject.logout();//模拟退出
        //System.out.println("是否执行了认证"+subject.isAuthenticated());
		subject.checkRoles("admin","user");//验证角色权限

简单逻辑为:

  1. 指定认证的数据
  2. 模拟添加用户
  3. 构建SecurityManager对象
  4. 主体提交认证请求
  5. SecurityManager认证
  6. Authenticator认证
  7. Realm认证

上面说到Realm认证分为三种:iniRealm、jdbcRealm、自定义Realm,下面编写相关代码(由于jdbcRealm大同小异,不列出代码了就)
iniRealm代码

public class iniRealmTest {
	public static void main(String[] args) {
		
		IniRealm iniRealm = new IniRealm("classpath:shirotest/user.ini");
		// 1:构建SecurityManager对象,还有一个jdbcrealm不一一演示了
		DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
		defaultSecurityManager.setRealm(iniRealm);
		
		// 2.主体提交认证请求
		SecurityUtils.setSecurityManager(defaultSecurityManager);// 构建SecurityManager环境
		Subject subject = SecurityUtils.getSubject();

		UsernamePasswordToken token = new UsernamePasswordToken("xingdo", "123456");
		subject.login(token);// 模拟登录
		System.out.println("是否执行了认证" + subject.isAuthenticated());
		subject.checkRole("admin");
		subject.checkPermissions("user:delete","user:select1");

	}
}

在resources下新建文件夹shirotest,再新建文件user.ini,代码如下

[users]
xingdo:123456,admin
[roles]
admin=user:delete,user:update,user:insert,user:select1

简介:

  • 指定认证数据有一些改变,去user.ini下验证数据,本人路径为:shirotest/user.ini,不一样的可自行更改
  • 将待验证数据交由SecurityManager处理:defaultSecurityManager.setRealm(iniRealm);

自定义Realm

public class myRealm extends AuthorizingRealm {

	Map<String, String> userMap = new HashMap<String, String>();

	{
		userMap.put("xingdo", "a0bc2e2dd7e719d5713a4b8e54a274b7");
		super.setName("myRealm");
	}

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		// 用来做授权
		String username = (String) principals.getPrimaryPrincipal();
		//从数据库中或者缓存中获取角色数据
		Set<String> roles = getRolesByUsername(username);
		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
		authorizationInfo.setRoles(roles);
		
		return authorizationInfo;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		// 用来做认证

		// 1,从主体传过来的认证信息中获取用户名,
		String username = (String) token.getPrincipal();

		// 2,通过用户名到数据库中获得密码
		String password = getpasswordByUsername(username);
		if (password == null) {
			return null;
		}
		SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo("xingdo", password, "myRealm");
		authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("xingdo"));//加盐的方法
		return authenticationInfo;
	}

	// 模拟数据库
	private String getpasswordByUsername(String username) {

		return userMap.get(username);
	}
	
	private Set<String> getRolesByUsername(String username){
		Set<String> roles = new HashSet<String>();
		roles.add("admin");
		roles.add("user");
		return roles;
		
	}

}

myRealm代码:

public class myRealmTest {
	public static void main(String[] args) {
		
		myRealm myRealm = new myRealm();
		
		// 构建SecurityManager对象,
		DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
		defaultSecurityManager.setRealm(myRealm);
		
		HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
		credentialsMatcher.setHashAlgorithmName("md5");//加密名称
		credentialsMatcher.setHashIterations(1);//加密次数
		myRealm.setCredentialsMatcher(credentialsMatcher);
		
		
		// 主体提交认证请求
		SecurityUtils.setSecurityManager(defaultSecurityManager);// 构建SecurityManager环境
		Subject subject = SecurityUtils.getSubject();

		UsernamePasswordToken token = new UsernamePasswordToken("xingdo", "123456");
		subject.login(token);// 模拟登录
		System.out.println("是否执行了认证" + subject.isAuthenticated());
		subject.checkRole("admin");
//		subject.checkPermissions("user:delete", "user:select1");
	}
}

整体逻辑:

  • 新建文件myRealm继承AuthorizingRealm并且实现doGetAuthorizationInfo方法和doGetAuthenticationInfo方法。其中doGetAuthorizationInfo用来做用来做授权,doGetAuthenticationInfo用来做认证。
  • 新建myRealmTest类,引用自定义的myRealm

doGetAuthorizationInfo、doGetAuthenticationInfo方法整体逻辑:

  1. 从主体传过来的认证信息中获取用户名,
  2. 从数据库中或者缓存中获取角色数据
  3. 构建SimpleAuthorizationInfo对象
  4. 将角色信息存放到SimpleAuthorizationInfo对象中并且返回信息

由于本次没有做mybatis集成,无法链接数据库,整体逻辑均使用的模拟数据库。将在下一篇文章中列出shiro与SpringBoot、mybatis的集成

至此整体shrio简单使用已经完成。现在互联网安全越来越重视,尤其是用户密码更是重中之重,那么shiro是怎么实现密码加密的呢?
shiro加密部分代码(该部分代码在myRealmTest中体现)

HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName("md5");//加密名称
credentialsMatcher.setHashIterations(1);//加密次数
myRealm.setCredentialsMatcher(credentialsMatcher);

MD5虽然无法反向解密,但是由于现在是大数据时代,将一些常见的密码和对应的加密字符串存放起来,根据字符串可以查找出未加密密码;这种情况加shrio推出了一种加”盐“的概念。即:在md5的基础上,新增一个字符串,用新增加的字符串和md5规则去加密。代码实现如下

authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("xingdo"));//加盐的方法

以上代码在myRealmTest中体现,xingdo即新增的字符串

猜你喜欢

转载自blog.csdn.net/java_xdo/article/details/88825119