身份验证,现在web中普遍都采用的机制,即在应用中证明我就是我本人。记得上大学那会儿写过一些小东西,登陆就是明文记录用户名密码,然后用户输入就登陆。其实想起来流程类似,不过Shiro显然高级很多。
功能简要介绍如下:
官方网站:shiro.apache.org,已经加入apache软件全家桶。
Apache Shiro(发音为“shee-roh”(西罗?),日语“堡垒(Castle)”的意思)是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理功能,可为任何应用提供安全保障 – 从命令行应用、移动应用到大型网络及企业应用。
Shiro为解决下列问题(我喜欢称它们为应用安全的四要素)提供了保护应用的API:
认证 – 用户身份识别,常被称为用户“登录”;
授权 – 访问控制;
密码加密 – 保护或隐藏数据防止被偷窥;
会话管理 – 每用户相关的时间敏感的状态。
Shiro还支持一些辅助特性,如Web应用安全、单元测试和多线程,它们的存在强化了上面提到的四个要素。
更多介绍,请查看 这里
在shiro中,用户需要提供principals (身份)和credentials(证明)给shiro,从而应用能验证用户身份:
principals:身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。一个主体可以有多个principals,但只有一个Primary principals,一般是用户名/密码/手机号。
credentials:证明/凭证,即只有主体知道的安全值,如密码/数字证书等。
最常见的principals和credentials组合就是用户名/密码了。接下来先进行一个基本的身份认证。
1、收集用户身份/凭证,即如用户名/密码;
2、调用Subject.login进行登录,如果失败将得到相应的AuthenticationException异常,根据异常提示用户错误信息;否则登录成功;
3、最后调用Subject.logout进行退出操作。
Shiro身份验证流程
1、Authenticator是真正的身份验证者,Shiro API中核心的身份认证入口点,此处可以自定义插入自己的实现;
2、Authenticator可能会委托给相应的AuthenticationStrategy进行多Realm身份验证,默认ModularRealmAuthenticator会调用AuthenticationStrategy进行多Realm身份验证;
3、Authenticator会把相应的token传入Realm,从Realm获取身份验证信息,如果没有返回/抛出异常表示身份验证失败了。此处可以配置多个Realm,将按照相应的顺序及策略进行访问。
Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。如我们之前的ini配置方式将使用org.apache.shiro.realm.text.IniRealm。
Shiro默认提供的Realm结构:
一般继承AuthorizingRealm(授权)即可。
我重写了org.apache.shiro.realm.jdbc.JdbcRealm实现,这个文件本身就包含一些关键features,只保留了加密方式和permissionsLookupEnabled等,在realm的bean声明:
<bean id="jdbcRealm" class="me.axiu.security.WebRealm"> <property name="name" value="jdbcRealm" /> <property name="permissionsLookupEnabled" value="true"/> <property name="credentialsMatcher" ref="sha256Matcher"/> <property name="authorizationCacheName" value="shiro.authorizationCache" /> </bean>
其中credentialsMatcher用于信任匹配,可用于加密密码的验证。采用SHA-256方式(更改hashAlgorithmName即可,可选MD5、SHA-1、SHA-256等),注意和数据库密码加密方式一致。还可以加盐(salt)来混淆密码。
<bean id="sha256Matcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <property name="hashAlgorithmName" value="SHA-256" /> <property name="storedCredentialsHexEncoded" value="true" /> <property name="hashIterations" value="2" /> </bean>
遇到一个问题,设置的unauthorizedUrl不会跳转,即碰到没有登陆的用户,会返回一个异常。一个解决办法是采用springframework的exceptionResolver来处理,相关代码如下:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="org.apache.shiro.authc.AuthenticationException">login</prop> <prop key="org.apache.shiro.authz.UnauthorizedException">nopermission</prop> <prop key="org.apache.shiro.authz.UnauthenticatedException">login</prop> <prop key="org.apache.shiro.authz.AuthorizationException">noperm</prop> </props> </property> </bean>