安全认证框架Shiro之认证

1. 集成Spring

导入Spring依赖包:spring-webmvc
在web.xml中配置监听、前端控制器
配置applicationContext.xml
        注解驱动
        扫描包
        视图转换器配前后缀
        静态资源访问

测试
        导入shiro包
        在web环境下配置shiro
        在web.xml中配置shiroFilter
        在applicationContext.xml配置shiro的核心组件:
DefaultWebSecurityManager
在这里插入图片描述
sessionMode可删掉。
在这里插入图片描述
这里需要加入EHcache的jar包及配置文件。

创建realm类,实现Realm接口,配置realm
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
anon表示可以被匿名访问,实际上是一个过滤芯器
authc必须认证(即登录)后才可能访问的页面
一般只配Login页和/**

1.1. 工作流程

        shiro提供与web集成的支持,其通过一个ShiroFilter入口来拦截需要安全控制的URL,然后进行相应的控制。
        ShiroFilter类似于如struts2/springmvc这种web框架的前端控制器,是安全控制的入口点,其负责读取配置(如ini配置文件),然后判断URL是否需要登录/权限等工作。

        ShiroFilter的工作原理:
        在这里插入图片描述
        在这里插入图片描述

1.2. 权限URL配置细节

1.2.1. 部分细节

        [urls]部分的配置,其格式是:“url=拦截器[参数], 拦截器[参数]”;
        如果当前请求的url匹配[urls]部分的某个url模式,将会执行其配置的拦截器。
        anon(anonymous)拦截器表示匿名访问(即不需要登录即可访问)。
        authc(authentication)拦截器表示需要身份认证通过后才能访问。

1.2.2. shiro中默认的过滤器

        过滤器名称: Anon
        过滤器类: org.apache.shiro.web.filter.authc.AnnonymousFilter
        概述: 没有参数,表示可以匿名使用
        例子:/admins/**=anon

1.2.3. url匹配模式


2. 认证

2.1. 认证实现流程

        (1)获取当前的subject:调用SecurityUtils.getSubject()获得。

Subject subject = SecrityUtils.getSubject();

        (2)测试当前的用户是否已经被认证,即是否已登录:调用subject.isAuthenticated()。

if(!subject.isAuthenticated())

        (3)若没有被认证,则把用户名和密码封装为UsernamepasswordToken对象:
                1)创建一个表单页面
                2)把请求提交到Controller
                3)获取用户名和密码

UsernamePasswordToken token = new UsernamePasswordToken(“admin”,123456);
token.setRemenberMe(true);

        (4)执行登录:调用subject.login(AuthenticationToken)方法。

subject.login(token);

        (5)自定义realm的方法,从数据库中获取对应的记录,返回给shiro:
                1)实际上需要继承org.apache.shiro.realm.AuthenticationRealm类
                2)实现doGetAuthenticationInfo(AuthenticationToken)方法

        (6)由shiro完成对密码的比对。

2.2. 认证方法中的实现步骤

        (1)把AuthenticationToken转换为UsernamePasswordToken
        (2)从UsernamePasswordToken中来获取username
        (3)调用数据库查询方法,从数据库中查询username对应的用户记录
        (4)若用户不存在,则可以抛出UnknowAccountException异常
        (5)根据用户信息情况,决定是否需要抛出其他的AuthenticationException异常
        (6)根据用户的情况,来构建AuthenticationInfo对象并返回。

2.3. 认证方法代码

@Override
properted Authentication doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException{
	UsernamePasswordToken upToken = (UsernamePasswordToken) token;
	String username = upToken.getUsername();
	User dbUser = UserService.getUserByName(username);
	
	//以下信息是从数据库中获取的:
	//(1) principal:认证的实体信息,可以是username,也可以是数据库对应的实体类对象
	Object principal = username;
	//(2) credentials:数据库返回的密码
	Object credentials = dbUser.getPassword();
	//(3) realmName:当前realm对象的name
	String realmName = getName();
	
	SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, realmName);
	return info;
}

2.4. 密码的对比

        问题:
        密码的比对是通过AuthenticatingRealm的credentialsMatche属性来进行密码的比对,而且还是明文直接比较的。这样其实是不安全的。shiro应该保存对密码加密后的,而不是明文的密码。

        源码:
        打开UsernamePasswordToken.class类,找到getPassword()方法,可在return password;行代码上加debug测试。测试截图:
        在这里插入图片描述
往下:
SimpleCredentialsMatcher.class
        在这里插入图片描述
找到下面的代码:
        这里获得登录输入用户名和密码的token对象,以及数据库获得的认证赁证对象,进行比较。
在这里插入图片描述
再往下:
在这里插入图片描述
AuthenticationRealm.class源码中找到:CredentialsMatcher()方法,用来比较密码:
在这里插入图片描述
credentialsMatcher(赁证匹配器)
我们发现Credentials提供了多种加密方式:
在这里插入图片描述
        shiro密码的对比:
        是通过AuthenticatingRealm类中的credenttialsMatcher属性来进行密码的比对。而且shiro默认加密方式为null,即不加密。


2.5. 密码的MD5加密

(1)什么是密码的加密?
        实际上就是在数据库表中保证密码不是能是明文,比方说不能是“123456”,而应该是“123456”加密之后的一个字符串,我们还要求这个加密算法是不可逆的,就是不能将这字符串反推回来密码是什么,如果能反推的话,这个加密就没什么意义了。著名的加密算法有MD5\SHA1。

        那接下来我们不禁要问:

(2)如何实现MD5加密?
        首先我们先看shiro源代码:

        MD5credentialsMatcher类:
在这里插入图片描述
该类是一个过时的类,它继承了HashedCredentialsMatcher类

我们想修改加密方式,可以修改它的HashAlgorithmName属性,该属性并不是MD5credentialsMatcher类的属性,是它的父类HashedCredentialsMatcher的属性,因此,我们在配置文件中找到Realm的配置,替换当前realm的credentialsMatcher属性。直接使用HashedCredentialsMatcher对象,并设置加密算法即可。
配置如下:
在这里插入图片描述
配置完赁证匹配器,也要将数据库里密码由明文修改为MD5加密的字符串。

(3)怎么加密的?
        这里可以查看HashedCredentialsMatcher.class类中的代码:
在这里插入图片描述
参数说明:
        hashAlgorithmName 加密算法: MD5
        credentials 加密前的密码: 123456
        salt 盐值: null 表示没有盐值
        hashIterations 加密次数: 加密1次是常见的,加密多次安全性越高。

打开SimpleHash.class类,查看构造方法:
在这里插入图片描述
在这里插入图片描述
可以在MyRealm中写个main方法,算下123456经过1024次MD5加密后的字符串是什么:
在这里插入图片描述
将得到的结果替换MyRealm中的密码:
在这里插入图片描述
        测试登录成功,这就是Shiro中MD5加密算法的配置。
        但实际上这里面也是存在问题的,什么问题?都搞了MD5加密,1024次加密,还是算法不可逆的,还不满意?

2.6. 密码的MD5盐值加密

(1)为什么使用MD5盐值加密?
        我们来看一个问题:如果两个人的密码都是123456,那加密后的字符串就是一样的。
        这有什么问题呢?如果是这样,我们的密码还是存在一定的风险性,那我们进一步要求:
        即便密码一样的,加密后的字符串也要不一样。

        怎么做到? 加点盐,味道就不一样了。

(2)如何实现盐值加密?
注意两个问题:
        1)加密之后的结果,应该把盐加进去
        2)在认证后得到的SimpleAuthenticationInfo 要将盐带上。

如何做到?
        1)在doGetAuthenticationInfo方法返回值创建SimpleAuthenticationInfo对象的时候,需要使用最复杂的带四个参的构造方法:SimleAuthenticationInfo(principal, credentials, credentialsSalt, realeName).
        2)使用ByteSource.Util.bytes()来计算盐值。
        3)盐值需要唯一:一般使用随机字符串或用户名
        4)使用new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations)来计算盐值加密后的密码值。

具体代码:

@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
	……
	//(1) principal:认证的实体信息,可以是username,也可以是数据表对应的用户的实体类对象
	Object principal = username;
	//(2) credentials: 密码
	Object credents = null;   //加密的字符串
	//(3),盐值
	//将用户名做为盐值进行加密
	ByteSource credentialsSalt = ByteSource.Util.bytes(username);  //Util是内部类
	//(4). realeName: 当前realm对象的name,调用父类的getName()方法即可
	String realmName = getName();
	
	SimpleAuthentictionInfo info = null;
	info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realeName);
	return info;
}

2.7. 多 Realm 验证

(1)为什么要多Realm证明?
        实际开发中,我们在某些特定场合我们需要将数据放在不同的数据库里,比方说MySQL中有,Oracle也可,那MySQL中的加密算法有MD5,而Oracle中的加密算法是sha1。那这个时候我们进行用户认证,要同时访问这两个数据库,需要多个Realm。如果有多个realm的话,还涉及到认证策略的问题。

(2)多realm怎么配?
        先查看下:ModularRealmAuthenticator.java类中的doAuthenticate()方法
在这里插入图片描述
具体配置步骤:
        1)再创建一个Realm文件:SecondRealm.class
                区分下SecondRealm与MyRealm,改一下代码以区分,如:修改SecondRealm中的加密方式为sha1。

测试获的加密后的数据:
在这里插入图片描述
        2)在applicatonContext.java中配置两个Realm:MyRealm和SecondRealm:
在这里插入图片描述
在这里插入图片描述
        3)新建一个Bean,用来加载多个realm。注意:这里我们一开始就将MyRealm给了SecurityManager,所以下面的ModularRealmAuthentiacator就不要配了。
在这里插入图片描述
        4)将上面“authenticator”做为SecurityManager的属性
在这里插入图片描述
注意:两个realm是有先后顺序的。

2.8. 认证策略

(1)为什么要认证策略?
        如果有多个realm,那怎样才算认证成功呢?这就是我们所谓的认证策略。

(2)认证策略有哪些?
        认证策略要实现AuthenticationStrategy接口,还有3个默认的实现。
                (1)FirstSuccesssfulStrategy:只要有一个Realm验证成功即可,只返回第一个realm身份验证成功的认证信息,其他的忽略。
                (2)AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,和FirstSuccessfulStrategy不同,将返回所有Realm身份验证成功的认证信息。
                (3)AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有Realm身份验证成功的认证信息,如果有一个失败就失败了。

        ModularRealmAuthenticator.class默认是AtLeastOneSuccessfulStrategy策略。
在这里插入图片描述
        debug测试可以看到aggregate的值是AtLeastOneSuccessfulStrategy

(3)如何修改认证策略?
        在applicationContext.xml中修改shiro的ModularRealmAuthenticatior的配置,如下:
在这里插入图片描述
上面代码修改了认证策略,将默认策略改成了AllSuccessfulStrategy。

2.9. 把 realms 配置给 SecurityManager

        前面的代码中,我们将2个realm配置给了ModularRealmAuthenticator,如下图:
在这里插入图片描述
现在我们要将这2个Realm配置给SecurityManager,如下图:
在这里插入图片描述
(1)我们为什么需要将他们改过来?
        因为我们在做授权的时候,需要SecurityManager去读Realms。

(2)为什么这样改没问题?
        在认证时候,调的是SecurityManager的Realms?还是authenticator的Realms?
        在认证时,调用的都是authenticator中的方法,包括调用Realms,但我们这里并没有给authenticator注入Realms,它为什么仍然可以正常读取Realms?
        因为在shiro初始化时,将Realms给了authenticator。
在这里插入图片描述

3. 上一篇:安全认证框架之Shiro详解

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Shiro框架是一个功能强大的Java安全框架,可以用于认证和授权。下面是使用Shiro进行认证和授权的基本步骤: 1. 添加Shiro依赖:在你的项目中添加Shiro的相关依赖,可以通过Maven或者Gradle进行引入。 2. 配置Shiro:创建一个Shiro的配置文件(通常是一个ini文件),配置Shiro的一些基本信息,例如Realm、Session管理等。你可以根据你的需求进行配置。 3. 创建Realm:Realm是Shiro用来进行认证和授权的核心组件。你需要实现一个自定义的Realm来实现用户的认证和授权逻辑。在Realm中,你可以通过重写相应的方法来实现自定义的认证和授权逻辑,例如验证用户名密码、查询用户角色和权限等。 4. 认证:在用户登录时,你可以通过调用Shiro提供的Subject.login方法来进行认证。该方法会将用户提交的用户名和密码传递给你自定义的Realm进行验证。如果验证通过,Shiro会将用户信息保存在Session中。 5. 授权:在用户进行操作时,你可以通过调用Shiro提供的Subject.hasRole和Subject.isPermitted方法来进行授权判断。这些方法会根据你在Realm中配置的角色和权限信息进行判断,决定用户是否具有相应的角色或权限。 以上是使用Shiro进行认证和授权的基本步骤,你可以根据具体的需求进行定制和扩展。在实际应用中,你还可以通过Shiro提供的其他功能,如RememberMe、Session管理等来增强安全性和用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值