`
jinnianshilongnian
  • 浏览: 21433801 次
  • 性别: Icon_minigender_1
博客专栏
5c8dac6a-21dc-3466-8abb-057664ab39c7
跟我学spring3
浏览量:2404932
D659df3e-4ad7-3b12-8b9a-1e94abd75ac3
Spring杂谈
浏览量:2997590
43989fe4-8b6b-3109-aaec-379d27dd4090
跟开涛学SpringMVC...
浏览量:5631404
1df97887-a9e1-3328-b6da-091f51f886a1
Servlet3.1规范翻...
浏览量:257542
4f347843-a078-36c1-977f-797c7fc123fc
springmvc杂谈
浏览量:1593136
22722232-95c1-34f2-b8e1-d059493d3d98
hibernate杂谈
浏览量:248958
45b32b6f-7468-3077-be40-00a5853c9a48
跟我学Shiro
浏览量:5847466
Group-logo
跟我学Nginx+Lua开...
浏览量:698110
5041f67a-12b2-30ba-814d-b55f466529d5
亿级流量网站架构核心技术
浏览量:780420
社区版块
存档分类
最新评论

第六章 Realm及相关对象——《跟我学Shiro》

阅读更多

 

目录贴: 跟我学Shiro目录贴

 

 

6.1 Realm

【2.5 Realm】及【3.5 Authorizer】部分都已经详细介绍过Realm了,接下来再来看一下一般真实环境下的Realm如何实现。

  

1、定义实体及关系


即用户-角色之间是多对多关系,角色-权限之间是多对多关系;且用户和权限之间通过角色建立关系;在系统中验证时通过权限验证,角色只是权限集合,即所谓的显示角色;其实权限应该对应到资源(如菜单、URL、页面按钮、Java方法等)中,即应该将权限字符串存储到资源实体中,但是目前为了简单化,直接提取一个权限表,【综合示例】部分会使用完整的表结构。

 

用户实体包括:编号(id)、用户名(username)、密码(password)、盐(salt)、是否锁定(locked);是否锁定用于封禁用户使用,其实最好使用Enum字段存储,可以实现更复杂的用户状态实现。

角色实体包括:、编号(id)、角色标识符(role)、描述(description)、是否可用(available);其中角色标识符用于在程序中进行隐式角色判断的,描述用于以后再前台界面显示的、是否可用表示角色当前是否激活。

权限实体包括:编号(id)、权限标识符(permission)、描述(description)、是否可用(available);含义和角色实体类似不再阐述。

 

另外还有两个关系实体:用户-角色实体(用户编号、角色编号,且组合为复合主键);角色-权限实体(角色编号、权限编号,且组合为复合主键)。

 

sql及实体请参考源代码中的sql\shiro.sql 和 com.github.zhangkaitao.shiro.chapter6.entity对应的实体。

 

2、环境准备

为了方便数据库操作,使用了“org.springframework: spring-jdbc: 4.0.0.RELEASE”依赖,虽然是spring4版本的,但使用上和spring3无区别。其他依赖请参考源码的pom.xml。

 

3、定义ServiceDao

为了实现的简单性,只实现必须的功能,其他的可以自己实现即可。

 

PermissionService

public interface PermissionService {
    public Permission createPermission(Permission permission);
    public void deletePermission(Long permissionId);
}

实现基本的创建/删除权限。

 

RoleService 

public interface RoleService {
    public Role createRole(Role role);
    public void deleteRole(Long roleId);
    //添加角色-权限之间关系
    public void correlationPermissions(Long roleId, Long... permissionIds);
    //移除角色-权限之间关系
    public void uncorrelationPermissions(Long roleId, Long... permissionIds);//
} 

相对于PermissionService多了关联/移除关联角色-权限功能。

 

UserService 

public interface UserService {
    public User createUser(User user); //创建账户
    public void changePassword(Long userId, String newPassword);//修改密码
    public void correlationRoles(Long userId, Long... roleIds); //添加用户-角色关系
    public void uncorrelationRoles(Long userId, Long... roleIds);// 移除用户-角色关系
    public User findByUsername(String username);// 根据用户名查找用户
    public Set<String> findRoles(String username);// 根据用户名查找其角色
    public Set<String> findPermissions(String username); //根据用户名查找其权限
} 

此处使用findByUsername、findRoles及findPermissions来查找用户名对应的帐号、角色及权限信息。之后的Realm就使用这些方法来查找相关信息。

 

UserServiceImpl  

public User createUser(User user) {
    //加密密码
    passwordHelper.encryptPassword(user);
    return userDao.createUser(user);
}
public void changePassword(Long userId, String newPassword) {
    User user =userDao.findOne(userId);
    user.setPassword(newPassword);
    passwordHelper.encryptPassword(user);
    userDao.updateUser(user);
} 

在创建账户及修改密码时直接把生成密码操作委托给PasswordHelper。

 

PasswordHelper

public class PasswordHelper {
    private RandomNumberGenerator randomNumberGenerator =
     new SecureRandomNumberGenerator();
    private String algorithmName = "md5";
    private final int hashIterations = 2;
    public void encryptPassword(User user) {
        user.setSalt(randomNumberGenerator.nextBytes().toHex());
        String newPassword = new SimpleHash(
                algorithmName,
                user.getPassword(),
                ByteSource.Util.bytes(user.getCredentialsSalt()),
                hashIterations).toHex();
        user.setPassword(newPassword);
    }
} 

之后的CredentialsMatcher需要和此处加密的算法一样。user.getCredentialsSalt()辅助方法返回username+salt。

 

为了节省篇幅,对于DAO/Service的接口及实现,具体请参考源码com.github.zhangkaitao.shiro.chapter6。另外请参考Service层的测试用例com.github.zhangkaitao.shiro.chapter6.service.ServiceTest。

 

4、定义Realm

RetryLimitHashedCredentialsMatcher 

和第五章的一样,在此就不罗列代码了,请参考源码com.github.zhangkaitao.shiro.chapter6.credentials.RetryLimitHashedCredentialsMatcher。

  

UserRealm

另外请参考Service层的测试用例com.github.zhangkaitao.shiro.chapter6.service.ServiceTest。 

public class UserRealm extends AuthorizingRealm {
    private UserService userService = new UserServiceImpl();
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = (String)principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(userService.findRoles(username));
        authorizationInfo.setStringPermissions(userService.findPermissions(username));
        return authorizationInfo;
    }
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String)token.getPrincipal();
        User user = userService.findByUsername(username);
        if(user == null) {
            throw new UnknownAccountException();//没找到帐号
        }
        if(Boolean.TRUE.equals(user.getLocked())) {
            throw new LockedAccountException(); //帐号锁定
        }
        //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以在此判断或自定义实现
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                user.getUsername(), //用户名
                user.getPassword(), //密码
                ByteSource.Util.bytes(user.getCredentialsSalt()),//salt=username+salt
                getName()  //realm name
        );
        return authenticationInfo;
    }
} 

1、UserRealm父类AuthorizingRealm将获取Subject相关信息分成两步:获取身份验证信息(doGetAuthenticationInfo)及授权信息(doGetAuthorizationInfo);

2、doGetAuthenticationInfo获取身份验证相关信息:首先根据传入的用户名获取User信息;然后如果user为空,那么抛出没找到帐号异常UnknownAccountException;如果user找到但锁定了抛出锁定异常LockedAccountException;最后生成AuthenticationInfo信息,交给间接父类AuthenticatingRealm使用CredentialsMatcher进行判断密码是否匹配,如果不匹配将抛出密码错误异常IncorrectCredentialsException;另外如果密码重试此处太多将抛出超出重试次数异常ExcessiveAttemptsException;在组装SimpleAuthenticationInfo信息时,需要传入:身份信息(用户名)、凭据(密文密码)、盐(username+salt),CredentialsMatcher使用盐加密传入的明文密码和此处的密文密码进行匹配。

3、doGetAuthorizationInfo获取授权信息:PrincipalCollection是一个身份集合,因为我们现在就一个Realm,所以直接调用getPrimaryPrincipal得到之前传入的用户名即可;然后根据用户名调用UserService接口获取角色及权限信息。

 

5、测试用例

为了节省篇幅,请参考测试用例com.github.zhangkaitao.shiro.chapter6.realm.UserRealmTest。包含了:登录成功、用户名错误、密码错误、密码超出重试次数、有/没有角色、有/没有权限的测试。

 

6.2 AuthenticationToken

AuthenticationToken用于收集用户提交的身份(如用户名)及凭据(如密码):

public interface AuthenticationToken extends Serializable {
    Object getPrincipal(); //身份
    Object getCredentials(); //凭据
} 

扩展接口RememberMeAuthenticationToken:提供了“boolean isRememberMe()”现“记住我”的功能;

扩展接口是HostAuthenticationToken:提供了“String getHost()”方法用于获取用户“主机”的功能。

 

Shiro提供了一个直接拿来用的UsernamePasswordToken,用于实现用户名/密码Token组,另外其实现了RememberMeAuthenticationToken和HostAuthenticationToken,可以实现记住我及主机验证的支持。

 

6.3 AuthenticationInfo

AuthenticationInfo有两个作用:

1、如果Realm是AuthenticatingRealm子类,则提供给AuthenticatingRealm内部使用的CredentialsMatcher进行凭据验证;(如果没有继承它需要在自己的Realm中自己实现验证);

2、提供给SecurityManager来创建Subject(提供身份信息);

 

MergableAuthenticationInfo用于提供在多Realm时合并AuthenticationInfo的功能,主要合并Principal、如果是其他的如credentialsSalt,会用后边的信息覆盖前边的。

 

比如HashedCredentialsMatcher,在验证时会判断AuthenticationInfo是否是SaltedAuthenticationInfo子类,来获取盐信息。

 

Account相当于我们之前的User,SimpleAccount是其一个实现;在IniRealm、PropertiesRealm这种静态创建帐号信息的场景中使用,这些Realm直接继承了SimpleAccountRealm,而SimpleAccountRealm提供了相关的API来动态维护SimpleAccount;即可以通过这些API来动态增删改查SimpleAccount;动态增删改查角色/权限信息。及如果您的帐号不是特别多,可以使用这种方式,具体请参考SimpleAccountRealm Javadoc。

 

其他情况一般返回SimpleAuthenticationInfo即可。

 

6.4 PrincipalCollection

因为我们可以在Shiro中同时配置多个Realm,所以呢身份信息可能就有多个;因此其提供了PrincipalCollection用于聚合这些身份信息:

public interface PrincipalCollection extends Iterable, Serializable {
    Object getPrimaryPrincipal(); //得到主要的身份
    <T> T oneByType(Class<T> type); //根据身份类型获取第一个
    <T> Collection<T> byType(Class<T> type); //根据身份类型获取一组
    List asList(); //转换为List
    Set asSet(); //转换为Set
    Collection fromRealm(String realmName); //根据Realm名字获取
    Set<String> getRealmNames(); //获取所有身份验证通过的Realm名字
    boolean isEmpty(); //判断是否为空
} 

因为PrincipalCollection聚合了多个,此处最需要注意的是getPrimaryPrincipal,如果只有一个Principal那么直接返回即可,如果有多个Principal,则返回第一个(因为内部使用Map存储,所以可以认为是返回任意一个);oneByType / byType根据凭据的类型返回相应的Principal;fromRealm根据Realm名字(每个Principal都与一个Realm关联)获取相应的Principal。

 

MutablePrincipalCollection是一个可变的PrincipalCollection接口,即提供了如下可变方法:

public interface MutablePrincipalCollection extends PrincipalCollection {
    void add(Object principal, String realmName); //添加Realm-Principal的关联
    void addAll(Collection principals, String realmName); //添加一组Realm-Principal的关联
    void addAll(PrincipalCollection principals);//添加PrincipalCollection
    void clear();//清空
} 

目前Shiro只提供了一个实现SimplePrincipalCollection,还记得之前的AuthenticationStrategy实现嘛,用于在多Realm时判断是否满足条件的,在大多数实现中(继承了AbstractAuthenticationStrategy)afterAttempt方法会进行AuthenticationInfo(实现了MergableAuthenticationInfo)的merge,比如SimpleAuthenticationInfo会合并多个Principal为一个PrincipalCollection。

 

对于PrincipalMap是Shiro 1.2中的一个实验品,暂时无用,具体可以参考其Javadoc。接下来通过示例来看看PrincipalCollection。

 

1、准备三个Realm

MyRealm1

public class MyRealm1 implements Realm {
    @Override
    public String getName() {
        return "a"; //realm name 为 “a”
    }
    //省略supports方法,具体请见源码
    @Override
    public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        return new SimpleAuthenticationInfo(
                "zhang", //身份 字符串类型
                "123",   //凭据
                getName() //Realm Name
        );
    }
}

         

MyRealm2 

和MyRealm1完全一样,只是Realm名字为b。

  

MyRealm3

public class MyRealm3 implements Realm {
    @Override
    public String getName() {
        return "c"; //realm name 为 “c”
    }
    //省略supports方法,具体请见源码
    @Override
    public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        User user = new User("zhang", "123");
        return new SimpleAuthenticationInfo(
                user, //身份 User类型
                "123",   //凭据
                getName() //Realm Name
        );
    }
} 

和MyRealm1同名,但返回的Principal是User类型。

 

2、ini配置(shiro-multirealm.ini)

[main]
realm1=com.github.zhangkaitao.shiro.chapter6.realm.MyRealm1
realm2=com.github.zhangkaitao.shiro.chapter6.realm.MyRealm2
realm3=com.github.zhangkaitao.shiro.chapter6.realm.MyRealm3
securityManager.realms=$realm1,$realm2,$realm3 

3、测试用例(com.github.zhangkaitao.shiro.chapter6.realm.PrincialCollectionTest

因为我们的Realm中没有进行身份及凭据验证,所以相当于身份验证都是成功的,都将返回:

Object primaryPrincipal1 = subject.getPrincipal();
PrincipalCollection princialCollection = subject.getPrincipals();
Object primaryPrincipal2 = princialCollection.getPrimaryPrincipal(); 

我们可以直接调用subject.getPrincipal获取PrimaryPrincipal(即所谓的第一个);或者通过getPrincipals获取PrincipalCollection;然后通过其getPrimaryPrincipal获取PrimaryPrincipal。

 

Set<String> realmNames = princialCollection.getRealmNames();

获取所有身份验证成功的Realm名字。      

 

Set<Object> principals = princialCollection.asSet(); //asList和asSet的结果一样

将身份信息转换为Set/List,即使转换为List,也是先转换为Set再完成的。

 

Collection<User> users = princialCollection.fromRealm("c");

根据Realm名字获取身份,因为Realm名字可以重复,所以可能多个身份,建议Realm名字尽量不要重复。

 

6.4 AuthorizationInfo

AuthorizationInfo用于聚合授权信息的:

public interface AuthorizationInfo extends Serializable {
    Collection<String> getRoles(); //获取角色字符串信息
    Collection<String> getStringPermissions(); //获取权限字符串信息
    Collection<Permission> getObjectPermissions(); //获取Permission对象信息
} 

当我们使用AuthorizingRealm时,如果身份验证成功,在进行授权时就通过doGetAuthorizationInfo方法获取角色/权限信息用于授权验证。

 

Shiro提供了一个实现SimpleAuthorizationInfo,大多数时候使用这个即可。

 

对于Account及SimpleAccount,之前的【6.3 AuthenticationInfo】已经介绍过了,用于SimpleAccountRealm子类,实现动态角色/权限维护的。

 

6.5 Subject

Subject是Shiro的核心对象,基本所有身份验证、授权都是通过Subject完成。

1、身份信息获取

Object getPrincipal(); //Primary Principal
PrincipalCollection getPrincipals(); // PrincipalCollection 

 

2、身份验证

void login(AuthenticationToken token) throws AuthenticationException;
boolean isAuthenticated();
boolean isRemembered();

通过login登录,如果登录失败将抛出相应的AuthenticationException,如果登录成功调用isAuthenticated就会返回true,即已经通过身份验证;如果isRemembered返回true,表示是通过记住我功能登录的而不是调用login方法登录的。isAuthenticated/isRemembered是互斥的,即如果其中一个返回true,另一个返回false。

  

3、角色授权验证 

boolean hasRole(String roleIdentifier);
boolean[] hasRoles(List<String> roleIdentifiers);
boolean hasAllRoles(Collection<String> roleIdentifiers);
void checkRole(String roleIdentifier) throws AuthorizationException;
void checkRoles(Collection<String> roleIdentifiers) throws AuthorizationException;
void checkRoles(String... roleIdentifiers) throws AuthorizationException; 

hasRole*进行角色验证,验证后返回true/false;而checkRole*验证失败时抛出AuthorizationException异常。 

 

4、权限授权验证

boolean isPermitted(String permission);
boolean isPermitted(Permission permission);
boolean[] isPermitted(String... permissions);
boolean[] isPermitted(List<Permission> permissions);
boolean isPermittedAll(String... permissions);
boolean isPermittedAll(Collection<Permission> permissions);
void checkPermission(String permission) throws AuthorizationException;
void checkPermission(Permission permission) throws AuthorizationException;
void checkPermissions(String... permissions) throws AuthorizationException;
void checkPermissions(Collection<Permission> permissions) throws AuthorizationException;

isPermitted*进行权限验证,验证后返回true/false;而checkPermission*验证失败时抛出AuthorizationException。

 

5、会话

Session getSession(); //相当于getSession(true)
Session getSession(boolean create);  

类似于Web中的会话。如果登录成功就相当于建立了会话,接着可以使用getSession获取;如果create=false如果没有会话将返回null,而create=true如果没有会话会强制创建一个。

 

6、退出 

void logout();

 

7、RunAs  

void runAs(PrincipalCollection principals) throws NullPointerException, IllegalStateException;
boolean isRunAs();
PrincipalCollection getPreviousPrincipals();
PrincipalCollection releaseRunAs(); 

RunAs即实现“允许A假设为B身份进行访问”;通过调用subject.runAs(b)进行访问;接着调用subject.getPrincipals将获取到B的身份;此时调用isRunAs将返回true;而a的身份需要通过subject. getPreviousPrincipals获取;如果不需要RunAs了调用subject. releaseRunAs即可。

 

8、多线程

<V> V execute(Callable<V> callable) throws ExecutionException;
void execute(Runnable runnable);
<V> Callable<V> associateWith(Callable<V> callable);
Runnable associateWith(Runnable runnable); 

实现线程之间的Subject传播,因为Subject是线程绑定的;因此在多线程执行中需要传播到相应的线程才能获取到相应的Subject。最简单的办法就是通过execute(runnable/callable实例)直接调用;或者通过associateWith(runnable/callable实例)得到一个包装后的实例;它们都是通过:1、把当前线程的Subject绑定过去;2、在线程执行结束后自动释放。

 

Subject自己不会实现相应的身份验证/授权逻辑,而是通过DelegatingSubject委托给SecurityManager实现;及可以理解为Subject是一个面门。

 

对于Subject的构建一般没必要我们去创建;一般通过SecurityUtils.getSubject()获取:

public static Subject getSubject() {
    Subject subject = ThreadContext.getSubject();
    if (subject == null) {
        subject = (new Subject.Builder()).buildSubject();
        ThreadContext.bind(subject);
    }
    return subject;
} 

即首先查看当前线程是否绑定了Subject,如果没有通过Subject.Builder构建一个然后绑定到现场返回。

 

如果想自定义创建,可以通过:

new Subject.Builder().principals(身份).authenticated(true/false).buildSubject()

这种可以创建相应的Subject实例了,然后自己绑定到线程即可。在new Builder()时如果没有传入SecurityManager,自动调用SecurityUtils.getSecurityManager获取;也可以自己传入一个实例。

 

对于Subject我们一般这么使用:

1、身份验证(login)

2、授权(hasRole*/isPermitted*或checkRole*/checkPermission*)

3、将相应的数据存储到会话(Session)

4、切换身份(RunAs)/多线程身份传播

5、退出

 

 

而我们必须的功能就是1、2、5。到目前为止我们就可以使用Shiro进行应用程序的安全控制了,但是还是缺少如对Web验证、Java方法验证等的一些简化实现。    

 

示例源代码:https://github.com/zhangkaitao/shiro-example;可加群134755960探讨Spring/Shiro技术。

 

46
8
分享到:
评论
27 楼 muzili90 2018-04-25  
我用mybatis持久层重新编写了这一章的demo 欢迎下载
下载地址 https://download.csdn.net/download/ttigerdna/10372917
源代码在项目com.myspring7z.framework.mybatisz.shiro.chapter6下
创建数据库脚本在com.myspring7z.framework.mybatisz.shiro.chapter6.test下
默认登录页面:http://localhost:8080/myspring7z/  
26 楼 snfdf 2017-05-13  
讲的真好,不过有点小小的问题
引用
因为PrincipalCollection聚合了多个,此处最需要注意的是getPrimaryPrincipal,如果只有一个Principal那么直接返回即可,如果有多个Principal,则返回第一个(因为内部使用Map存储,所以可以认为是返回任意一个);

PrincipalCollection内部是使用Map存储,但使用的是LinkedHashMap,所以取出来的一定是第一个。
25 楼 shanxianyue 2016-12-15  
changxianbest 写道
我五年开发经验,我自认为我的开发水平在同工作年限的人中还算是出类拔萃的,怎么我就觉得开涛的文章读得不是太懂啊,能不能先把实际项目怎么搞shiro,搞个demo跑起来?

debug,跟着看一下
24 楼 cser245086272 2016-09-05  
赞赞赞,写的非常好。1-6看的都看的非常明白,再配合源码,可以给自己一个思路,很不错。向楼主学习  
23 楼 a87604476 2016-07-18  
MergableAuthenticationInfo用于提供在多Realm时合并AuthenticationInfo的功能,主要合并Principal、如果是其他的如credentialsSalt,会用后边的信息覆盖前边的。楼主,这句话没看明白
22 楼 xiaoliuf4565 2016-01-16  
博主讲的很好,难为了,在这么短的篇幅里讲解这么多知识点,如果一路看过来还好,如果直接到这章来看,估计得绕晕了去
21 楼 u011248489 2015-11-09  
只笑一笑 写道
tao哥,这个UserRealmTest的方法中:
1、测试时,是不是没测都要首先执行以下BaseTest中的@Before注解的方法
2、如果执行,那要验证的怎么与数据库中的密码匹配
3、不执行(注释@Before),那么
u1 = new User("zhang", "12");//此处的密码可以完全适配
login("classpath:06_shiro.ini", u1.getUsername(), password);

最后,在登录验证时,那个passwordHelp中的密码操作方法,执行吗?为什么?

只笑一笑 写道
tao哥,这个UserRealmTest的方法中:
1、测试时,是不是没测都要首先执行以下BaseTest中的@Before注解的方法
2、如果执行,那要验证的怎么与数据库中的密码匹配
3、不执行(注释@Before),那么
u1 = new User("zhang", "12");//此处的密码可以完全适配
login("classpath:06_shiro.ini", u1.getUsername(), password);

最后,在登录验证时,那个passwordHelp中的密码操作方法,执行吗?为什么?


本人理解,passwordHelp只是加密密码用的,验证时不需要,你看shiro.ini定义的credentialsMatcher跟passwordHelp中加密方式是一样的,这样两者就可以比对验证了。
20 楼 只笑一笑 2015-10-20  
tao哥,这个UserRealmTest的方法中:
1、测试时,是不是没测都要首先执行以下BaseTest中的@Before注解的方法
2、如果执行,那要验证的怎么与数据库中的密码匹配
3、不执行(注释@Before),那么
u1 = new User("zhang", "12");//此处的密码可以完全适配
login("classpath:06_shiro.ini", u1.getUsername(), password);

最后,在登录验证时,那个passwordHelp中的密码操作方法,执行吗?为什么?
19 楼 罗潇_Javaol 2015-08-11  
changxianbest 写道
我五年开发经验,我自认为我的开发水平在同工作年限的人中还算是出类拔萃的,怎么我就觉得开涛的文章读得不是太懂啊,能不能先把实际项目怎么搞shiro,搞个demo跑起来?

在github上下下来弄起来。
18 楼 zc40312018 2015-08-05  
zc40312018 写道
@Test(expected = LockedAccountException.class)
public void testLoginFailWithLocked() {
   login("classpath:shiro.ini", u4.getUsername(), password + "1");
}
代码中 password 不用 再拼 1了吧

@Test(expected = ExcessiveAttemptsException.class)
public void testLoginFailWithLimitRetryCount() {
    for(int i = 1; i <= 5; i++) {
        try {
            login("classpath:shiro.ini", u3.getUsername(), password + "1");
        } catch (Exception e) {/*ignore*/}
    }
    login("classpath:shiro.ini", u3.getUsername(), password + "1");

    //需要清空缓存,否则后续的执行就会遇到问题(或者使用一个全新账户测试)
}

我的报
java.lang.Exception: Unexpected exception, expected<org.apache.shiro.authc.ExcessiveAttemptsException> but was<org.apache.shiro.authc.IncorrectCredentialsException>
at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:31)

这个错误,这个是什么原因?


不好意思,开涛,后面那个问题我找到原因了,是本人手误造成的
17 楼 zc40312018 2015-08-05  
@Test(expected = LockedAccountException.class)
public void testLoginFailWithLocked() {
   login("classpath:shiro.ini", u4.getUsername(), password + "1");
}
代码中 password 不用 再拼 1了吧

@Test(expected = ExcessiveAttemptsException.class)
public void testLoginFailWithLimitRetryCount() {
    for(int i = 1; i <= 5; i++) {
        try {
            login("classpath:shiro.ini", u3.getUsername(), password + "1");
        } catch (Exception e) {/*ignore*/}
    }
    login("classpath:shiro.ini", u3.getUsername(), password + "1");

    //需要清空缓存,否则后续的执行就会遇到问题(或者使用一个全新账户测试)
}

我的报
java.lang.Exception: Unexpected exception, expected<org.apache.shiro.authc.ExcessiveAttemptsException> but was<org.apache.shiro.authc.IncorrectCredentialsException>
at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:31)

这个错误,这个是什么原因?
16 楼 changxianbest 2015-04-16  
我五年开发经验,我自认为我的开发水平在同工作年限的人中还算是出类拔萃的,怎么我就觉得开涛的文章读得不是太懂啊,能不能先把实际项目怎么搞shiro,搞个demo跑起来?
15 楼 798881262 2015-03-07  
[color=orange][/color]ggggggggggggg'
14 楼 gugu_abrams 2014-08-09  
realm中注入的这个service,是由jdk代理的,而不是spring,这时候service中的事务没有用了吧。。。

p.s.
为什么shiro官方的例子里realm注入的是dao?

13 楼 jinnianshilongnian 2014-04-12  
suu 写道
如果create=true如果没有会话将返回null,而create=true如果没有会话会强制创建一个。
-----tao哥,这里写错了吧

是 谢谢啊
12 楼 suu 2014-04-12  
如果create=true如果没有会话将返回null,而create=true如果没有会话会强制创建一个。
-----tao哥,这里写错了吧
11 楼 caojb1024 2014-03-14  
    
10 楼 kolenxiao 2014-03-03  
博主写得非常好,俺受益了,顶一个!
9 楼 jinnianshilongnian 2014-02-27  
jinnianshilongnian 写道
maoweiwer 写道
请问开涛的ES脚手架中是使用的你所讲的shiro模式来实现的权限管理吗

该系列毕竟是教程之类,不会像es那么复杂;不过在该教程示例的基础上扩展下应用到项目中是没问题;es的权限还是复杂点,本教程可以认为是它的一个子集吧。

不过,看完本教程,再去看es权限那部分问题不大
8 楼 jinnianshilongnian 2014-02-27  
maoweiwer 写道
请问开涛的ES脚手架中是使用的你所讲的shiro模式来实现的权限管理吗

该系列毕竟是教程之类,不会像es那么复杂;不过在该教程示例的基础上扩展下应用到项目中是没问题;es的权限还是复杂点,本教程可以认为是它的一个子集吧。

相关推荐

    shiro第六章Realm完整Demo

    shiro第六章Realm完整Demo

    跟我学shiro文档和示例源代码

    跟我学shiro文档和示例源代码 第一章 SHIRO 简介....................................................................................................................... 5 简介 ...............................

    shiro-realm案例

    shiro自定义realm案例,参考文档:http://blog.csdn.net/qq_19558705/article/details/50775509

    Shiro学习教程源代码

    第六章 Realm及相关对象 第七章 与Web集成 第八章 拦截器机制 第九章 JSP标签 第十章 会话管理 第十一章 缓存机制 第十二章 与Spring集成 第十三章 RememberMe 第十四章 SSL 第十五章 单点登录 第十六章 综合实例 第...

    shiro web中自定义Realm

    这里是shiro在web应用中自定义Realm的代码,以便做一个参考

    从实例入手学习Shiro自定义Realm实现查询数据进行验证示例代码.zip

    从实例入手学习Shiro自定义Realm实现查询数据进行验证示例代码.zip

    Shiro基本使用详解以及多Realm使用和配置.rar

    Shiro基本使用详解以及多Realm使用和配置,拿来可以直接使用,也可以在此基础上进行自己业务逻辑的添加和修改,如果希望进一步深入学习,可以查看我的博客,可以查看...或给我留言

    尚硅谷Shiro视频教程

    · 00.尚硅谷_Shiro_源码、课件 · 01.尚硅谷_Shiro_简介 · 02.尚硅谷_Shiro_HelloWorld · 03.尚硅谷_Shiro_集成 Spring · 04....尚硅谷_Shiro_认证和记住我的区别 · 27.尚硅谷_Shiro_实现Rememberme

    Apache_Shiro_使用手册(四)Realm_实现

    Apache_Shiro_使用手册(四)Realm_实现

    shiro权限框架自定义Realm示例

    shiro权限框架自定义Realm示例

    shiro入门学习demo源码

    &lt;bean id="myShiroRealm" class="com.z.shiro.realm.ShiroRealm"&gt; &lt;property name="cacheManager" ref="cacheManager" /&gt; &lt;/bean&gt; &lt;!-- Shiro Filter --&gt; &lt;bean id="shiroFilter" class="org.apache...

    Shiro 视频教程+源码+课件

    第一章 问候 Shiro 他大爷 1.Shiro 简介 2.ShiroHelloWorld 实现 第二章 身份认证 1.Subject 认证主体 2.身份认证流程 第三章 权限认证 1.权限认证核心要素 2.授权 3.Permissions 对权限深入理解 4.授权流程 ...

    shiro授权 shiro和企业项目整合开发

    shiro授权,自定义realm,shiro与项目整合,shiro缓存,验证码,记住我

    吴天雄--shiro个人总结笔记.doc

    shiro标签,第六讲 自定义Realm(加入整合spring和MyBatis), 第七讲 加密(加密算法、加密过程、加密实现代码),第八讲 记住我,第九讲 缓存管理(代码实现),第十讲 会话管理(session的监听和检测、环境配置)...

    Shiro原理+配置

    但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着"当前跟软件交互的东西"。但考虑到大多数目的和用途,你可以把它认为是Shiro的"用户...

    用于测试shiro中自定义Realm的测试代码

    这个程序是eclipse编写的,学习shiro框架,入门的,用于测试自定义的Realm的小例子,仅仅用于学习,不得用于商业用途

    shiro demo 实例 jdbcRealm

    shiro demo 源码里面2中realm 一种是jdbcRealm 一种是自定义realm 有sql脚本。请看db文件夹下的readme.txt 有关这个项目的详细介绍,使用了简单的标签库权限控制当做例子

    shiro教程文档-张开涛

    shiro文档张开涛,文档详细,层次分明。Shiro 简介、身份验证、授权、INI 配置、编码/加密、Realm 及相关对象、与 Web 集成.....

    shiro 教程

    第二章:Shiro入门 包括:是什么、能干什么、有什么、高层概览架构、完整架构、HelloWorld 第三章:Shiro的配置 包括:程序配置、ini配置的方式(包括各个部分的配置)、权限字符串方式等 第四章:Shiro的身份认证...

    Shiro学习第一式身份验证2

    Shiro学习第一式身份验证,关于单个Realm,多个Realm以及JDBC Realm之类的,有需要的下了,免积分!

Global site tag (gtag.js) - Google Analytics