Shiro笔记身份验证

Posted Shadowplay

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Shiro笔记身份验证相关的知识,希望对你有一定的参考价值。

Shiro笔记(二)身份验证

一、核心代码

 1 @Test
 2     public void helloWorldTest(){
 3         IniSecurityManagerFactory factory =
 4                 new IniSecurityManagerFactory("classpath:shiro-jdbc-realm.ini");
 5         SecurityManager manager = factory.getInstance();
 6        //全局设置,一次即可
 7         SecurityUtils.setSecurityManager(manager);
 8         Subject subject = SecurityUtils.getSubject();
 9         UsernamePasswordToken token =
10                 new UsernamePasswordToken("Peter", "123");
11         try{
12                subject.login(token);
13             }catch (AuthenticationException e){
14                 e.printStackTrace();
15             }
16 
17         Assert.assertEquals(true,subject.isAuthenticated());
18         //退出登录
19         subject.logout();

shiro.ini文件:

[users]
Peter=123
Tom=321

二、身份认证流程:

Authenticator 可能会委托给相应的 AuthenticationStrategy 进行多 Realm 身份验证,默认
ModularRealmAuthenticator 会调用 AuthenticationStrategy 进行多 Realm 身份验证;
Authenticator 会把相应的 token 传入 Realm,从 Realm 获取身份验证信息

 三、Realm

Shiro 从从 Realm 获取安全数据(如用户、角色、权限)

Reaml接口:

1 public interface Realm {
2     //获得唯一的名字
3     String getName();
4     //判断此realm是否支持此token
5     boolean supports(AuthenticationToken token);
6     //获取token认证信息
7     AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException;
8 }

一)单Realm配置

 1 public class MyRealm implements Realm{
 2 
 3     public String getName() {
 4         return "myRealm";
 5     }
 6 
 7     public boolean supports(AuthenticationToken authenticationToken) {
 8         //仅支持UsernamePasswordToken类型
 9         return authenticationToken instanceof UsernamePasswordToken;
10     }
11 
12     public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
13         //获取用户名
14         String username= (String) token.getPrincipal();
15         //获取密码
16         String password=new String((char[]) token.getCredentials());
17         if(!"Peter".equals(username)){
18             throw new UnknownAccountException();
19         }
20         if(!"123".equals(password)){
21             throw new IncorrectCredentialsException();
22         }
23         return new SimpleAuthenticationInfo(username,password,getName());
24     }
25 }

ini文件指定:

1 myRealm=com.tang.shirotest.LoginLogoutTest
2 securityManager.realms=$myRealm

二)JDBC Realm的使用

1 [main]
2 jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
3 dataSource=com.alibaba.druid.pool.DruidDataSource
4 dataSource.driverClassName=com.mysql.jdbc.Driver
5 dataSource.url=jdbc:mysql://localhost:3306/shiro
6 dataSource.username=root
7 dataSource.password=jiapi1990
8 jdbcRealm.dataSource=$dataSource
9 securityManager.realms=$jdbcRealm

 

三)Authenticator及AuthenticationStrategy

Authenticator的职责是验证用户账号,接口为:

public interface Authenticator {
    AuthenticationInfo authenticate(AuthenticationToken var1) throws AuthenticationException;
}

SecurityManager 接口继承了 Authenticator,另外还有一个 ModularRealmAuthenticator 实现,
其委托给多个 Realm 进行验证,验证规则通过 AuthenticationStrategy 接口指定,默认提供
的实现:
FirstSuccessfulStrategy:只要有一个 Realm 验证成功即可,只返回第一个 Realm 身份验证
成功的认证信息,其他的忽略;
AtLeastOneSuccessfulStrategy:只要有一个 Realm 验证成功即可,和 FirstSuccessfulStrategy
不同,返回所有 Realm 身份验证成功的认证信息;
AllSuccessfulStrategy:所有 Realm 验证成功才算成功,且返回所有 Realm 身份验证成功的
认证信息,如果有一个失败就失败了

ModularRealmAuthenticator 默认使用 AtLeastOneSuccessfulStrategy 策略。

ini文件:

 1 #指定 securityManager 的 authenticator 实现
 2 authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
 3 securityManager.authenticator=$authenticator
 4 #指定 securityManager.authenticator 的 authenticationStrategy
 5 allSuccessfulStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy
 6 securityManager.authenticator.authenticationStrategy=$allSuccessfulStrategy
 7 myRealm1=com.github.zhangkaitao.shiro.chapter2.realm.MyRealm1
 8 myRealm2=com.github.zhangkaitao.shiro.chapter2.realm.MyRealm2
 9 myRealm3=com.github.zhangkaitao.shiro.chapter2.realm.MyRealm3
10 securityManager.realms=$myRealm1,$myRealm3

 

AuthenticationStrategy接口:

 1 public interface AuthenticationStrategy {
 2     //在所有 Realm 验证之前调用
 3     AuthenticationInfo beforeAllAttempts(Collection<? extends Realm> realms, AuthenticationToken token) throws AuthenticationException;
 4     //在每个 Realm 之前调用
 5     AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException;
 6     //在每个 Realm 之后调用
 7     AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t)
 8             throws AuthenticationException;
 9     ////在所有 Realm 之后调用
10     AuthenticationInfo afterAllAttempts(AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException;
11 }

自定义实现:

 1 public class AtLeastTwoAuthenticatorStrategy extends AbstractAuthenticationStrategy {
 2 
 3     @Override
 4     public AuthenticationInfo beforeAllAttempts(Collection<? extends Realm> realms, AuthenticationToken token) throws AuthenticationException {
 5         return new SimpleAuthenticationInfo();//返回一个权限的认证信息
 6     }
 7 
 8     @Override
 9     public AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException {
10         return aggregate;//返回之前合并的
11     }
12 
13     @Override
14     public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException {
15         AuthenticationInfo info;
16         if (singleRealmInfo == null) {
17             info = aggregateInfo;
18         } else {
19             if (aggregateInfo == null) {
20                 info = singleRealmInfo;
21             } else {
22                 info = merge(singleRealmInfo, aggregateInfo);
23             }
24         }
25 
26         return info;
27     }
28 
29     @Override
30     public AuthenticationInfo afterAllAttempts(AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException {
31         if (aggregate == null || CollectionUtils.isEmpty(aggregate.getPrincipals()) || aggregate.getPrincipals().getRealmNames().size() < 2) {
32             throw new AuthenticationException("Authentication token of type [" + token.getClass() + "] " +
33                     "could not be authenticated by any configured realms.  Please ensure that at least two realm can " +
34                     "authenticate these tokens.");
35         }
36 
37         return aggregate;
38     }
39 }

 

以上是关于Shiro笔记身份验证的主要内容,如果未能解决你的问题,请参考以下文章

Shiro 学习笔记——shiro身份验证

Shiro笔记基本概念

Shiro 学习笔记——shiro简介

Shiro学习笔记

使用 Facebook OAuth 进行 Apache Shiro 身份验证

Shiro01 功能点框图架构图身份认证逻辑身份认证代码实现