Shiro学习:关于shiro安全框架的登录和获取用户对象

最近用在用apache shiro在做权限管理,网上很多博客的登录部分都是这么写的

这是重写authorizingrealm的dogetAuthenticationinfo方法:
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// TODO Auto-generated method stub
    String username=(String) token.getPrincipal();
    User user=userService.getUserByUsername(username);
    if(user==null){
        throw new UnknownAccountException();
    }
    if(user.getUserState()==4){
        throw new LockedAccountException();
    }
    SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(
    user.getUsername(),
    user.getPassword(),
    ByteSource.Util.bytes(user.getCredentialsSalt()),
    this.getName()
    );

    return info;
} 
网上很多教程都是这么教给大家的, 然后在controller里用:
UsernameAndPasswordToken token=new UsernameAndPasswordToken(username,password);
subject.login(token);
....

之前在找相关资料学习的时候,看到SimpleAuthenticationInfo的第一个参数原来可以传对象,有大作用,于是就思考岂不是不用手动往session中写User对象了?然后试了一下,发现不知道为什么,直接传user对象进去,一直报String的类型错误。如下:


SimpleAuthenticationInfo aInfo = new SimpleAuthenticationInfo(user, user.getPassword(),ByteSource.Util.bytes(user.getUsername()), getName());

我们看下这个SimpleAuthenticationInfo的一个构造方法,这里第一个参数就是你刚才传入的用户名,第二个参数就是你传入的密码,但是方法定义中这两个参数都是Object类型,尤其是第一个principal参数,它的意义远远不止用户名那么简单,它是用户的所有认证信息集合,登陆成功后,标签一旦有property属性,PrincipalTag类也就是标签的支持类,会从Subject的principalcollection里将principal取出,取出的就是你传入的第一个参数,如果你传了个string类型的用户名,那么你只能获取用户名。此处参考大牛的链接https://blog.csdn.net/ccdust/article/details/52300287

public SimpleAuthenticationInfo(Object principal, Object hashedCredentials, ByteSource credentialsSalt, String realmName) {
        this.principals = new SimplePrincipalCollection(principal, realmName);
        this.credentials = hashedCredentials;
        this.credentialsSalt = credentialsSalt;
    }

所以现在知道该怎么做了吧?构建一个list,第一个元素是用户名,第二个元素是user对象。第一个元素用来登陆,第二个元素用来获取登陆后user对象的属性。
在realm里这么写:

		// 存入用户信息
		List principals = new ArrayList();
		principals.add(user.getUsername());
		principals.add(user);


		SimpleAuthenticationInfo aInfo = new SimpleAuthenticationInfo(principals, user.getPassword(),
				ByteSource.Util.bytes(user.getUsername()), getName()); 
  

测试之后终于成功了,获取user对象信息如下:

		// 测试
		User user =  SecurityUtils.getSubject().getPrincipals().oneByType(User.class);
		System.out.println("user测试:" + user.toString());

那么问题来了,值是进去了,后台程序也能使用,那我们怎么通过标签在前台获取user对象里的属性?

我们先看标签源码,打开PrincipalTag类,看到onDoStartTag方法:

    public int onDoStartTag() throws JspException {
        String strValue = null;
 
        if (getSubject() != null) {
 
            // Get the principal to print out
            Object principal;
 
            if (type == null) {
                principal = getSubject().getPrincipal();
            } else {
                principal = getPrincipalFromClassName();
            }
 
            // Get the string value of the principal
            if (principal != null) {
                if (property == null) {
                    strValue = principal.toString();
                } else {
                    strValue = getPrincipalProperty(principal, property);
                }
            }
 
        }
 
        // Print out the principal value if not null
        if (strValue != null) {
            try {
                pageContext.getOut().write(strValue);
            } catch (IOException e) {
                throw new JspTagException("Error writing [" + strValue + "] to JSP.", e);
            }
        }
 
        return SKIP_BODY;
    } 

看到那个Object principal这个方法变量了么?如果标签里没有type属性,那么就直接调用getPrincipal方法,再打开这个方法,看到subject里是这么写的:

    public Object getPrincipal() {

        return getPrimaryPrincipal(getPrincipals());

    } 


getPrincipals是获取principalcollection,getprimaryprincipal就是获取这个principalcollection的第一个元素,用的是迭代器的方式获取。具体的我不列出来了,请参见SimplePrincipalcollection的源代码。
第一个元素你最初放的是用户名,所以你可以取得这个用户名。 如果type不为空,就会去principalcollection中找和这个type类型一致的一个对象,看源码:

    private Object getPrincipalFromClassName() {

        Object principal = null;



        try {

            Class cls = Class.forName(type);

            principal = getSubject().getPrincipals().oneByType(cls);

        } catch (ClassNotFoundException e) {

            if (log.isErrorEnabled()) {

                log.error("Unable to find class for name [" + type + "]");

            }

        }

        return principal;

    } 


那个oneByType方法就是在principalcollection中找和type属性一致的那个类的对象,将其作为principal,如果标签有了property属性,然后用java内省机制获取bean的属性,参见getPrincipalProperty方法,因为方法体太长我就不列出了。

看了这些源码之后,我相信你也知道该怎么获取了吧,代码如下:

也就是根据type去principalcollection中找和type属性一致的那个类的对象,然后用getPrincipalProperty获取对应的属性

 

就写这么多吧,希望大家看了能有启发。特此复制和整理了别人解决办法的博客  附上 大牛的链接  https://blog.csdn.net/ccdust/article/details/52300287

你可能感兴趣的:(shiro,javaweb,ssm,后端,java)