shiro(二)身份验证 基于ini文件

简单的身份验证 

  • principals:身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。一个主体可以有多个 principals,但只有一个 Primary principals,一般是用户名/密码/手机号。
  • credentials:证明/凭证,即只有主体知道的安全值,如密码/数字证书等。
  • 最常见的 principals 和 credentials 组合就是用户名/密码了。

shiro.ini 准备身份/凭证

[users]部分指定用户名/密码及其角色;

[roles]部分指定角色即权限信息;

#定义用户
[users]
zhang=12345
wang=abc
package ini_shiro;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;

public class SimpleTest {
	public static void main(String[] args) {
		/* 1. 获取SecurityManager工厂,通过ini文件  */
		Factory<org.apache.shiro.mgt.SecurityManager> factory = new IniSecurityManagerFactory("classpath:simpleshiro.ini");
		//2.获得安全管理者实例,放入SecurityUtils(全局设置,一次即可)
		org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();
		SecurityUtils.setSecurityManager(securityManager);
		//3.得到Subject,自动绑定到当前线程(web项目要 在请求结束时解除绑定)得到当前用户的身份/凭证,
		Subject subject = SecurityUtils.getSubject();
		UsernamePasswordToken token = new UsernamePasswordToken("zhang","12345");
		try {
			//4.进行身份验证
			subject.login(token);//委托 SecurityManager.login
		}catch(AuthenticationException e) {
			System.out.println("身份验证失败");
		}
		
		if(subject.isAuthenticated()) {//为true表示验证成功
			System.out.println("验证成功");
			subject.logout();//身份登出
			System.out.println("登出");
		}
	}
}

                更改密码,

可捕 获 AuthenticationException 或 其 子 类 , 常 见 的 如 :
DisabledAccountException(禁用的帐号)、LockedAccountException(锁定的帐号)、
UnknownAccountException(错误的帐号)、ExcessiveAttemptsException(登录失败次数过
多)、IncorrectCredentialsException (错误的凭证)、ExpiredCredentialsException(过期的
凭证)等,具体请查看其继承关系;对于页面的错误消息展示,最好使用如“用户名/密码
错误”而不是“用户名错误”/“密码错误”,防止一些恶意用户非法扫描帐号库;

 shrio.ini

#定义安全相关的数据
#用户
[users]
zhang3 =12345,admin

li4=abcde,productManager
#角色和权限
[roles]
#admin什么都能做
admin=*
#productManager做Product相关
productManager = addProduct,deleteProduct,updateProduct,selectProduct
#orderManager做Product相关
orderManager = addOrder,deleteOrder,updateOrder,selectOrder

User

package ini_shiro;

public class User {
	 private int id;
	 	private String name;
	    private String password;
	    public int getId() {
			return id;
		}
		public void setId(int id) {
			this.id = id;
		}
	    public String getName() {
	        return name;
	    }
	    public void setName(String name) {
	        this.name = name;
	    }
	    public String getPassword() {
	        return password;
	    }
	    public void setPassword(String password) {
	        this.password = password;
	    }
		public User(String name, String password) {
			super();
			this.name = name;
			this.password = password;
		}
		public User() {
			super();
		}
	    
}

Test

package ini_shiro;

import java.util.ArrayList;
import java.util.List;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.apache.shiro.mgt.SecurityManager;
public class Test {
public static void main(String[] args) {
	/**
	 * 准备三个用户,两个定义了,一个没有
	 */
	User zhang3 = new User();
	zhang3.setName("zhang3");
    zhang3.setPassword("12345");
    
    User li4 = new User();
    li4.setName("li4");
    li4.setPassword("abcde");
    
    User wang5 = new User("wang5","wrong");//没有定义在shiro.ini中
    
    List<User> users = new ArrayList<>();
    users.add(zhang3);
    users.add(li4);
    users.add(wang5);
    
    //定义角色
    String roleAdmin = "admin";
    String roleProductManager ="productManager"; 
    List<String> roles = new ArrayList<>();
    roles.add(roleAdmin);
    roles.add(roleProductManager);
    
    
    //定义权限
    String permitProduct = "addProduct"; 
    String permitOrder = "addOrder"; 
    List<String> permits = new ArrayList<>();
    permits.add(permitProduct);
    permits.add(permitOrder);
    
    //登陆每个用户
    for (User user : users) {
        if(login(user))
            System.out.printf("%s \t登陆成功,用的密码是 %s\t %n",user.getName(),user.getPassword());
        else
            System.out.printf("%s \t登录失败,用的密码是 %s\t %n",user.getName(),user.getPassword());
    }
     
    System.out.println("----分割线------");
     
    //判断能够登录的用户是否拥有某个角色
    for (User user : users) {
        for (String role : roles) {
            if(login(user)) {
                if(hasRole(user, role))
                    System.out.printf("%s\t 拥有角色: %s\t%n",user.getName(),role);
                else
                    System.out.printf("%s\t 不拥有角色: %s\t%n",user.getName(),role);
            }
        }  
    }
    System.out.println("------ 分割线------");

    //判断能够登录的用户,是否拥有某种权限
   for(User user:users) {
	   for(String role:roles) {
		   for(String permit:permits) {
			   if(login(user)) {
				   if(hasRole(user, role)) {
					   if(isPermitted(user, permit)) {
						   System.out.printf("%s\t 拥有权限:%s ",user.getName(),permit);
					   }
					   else
						   System.out.printf("%s\t 没有权限:%s ",user.getName(),permit);
				   }
			   }
		   }
	   }
   }
}

//获取当前用户
private static Subject getSubject(User user) {
    //加载配置文件,并获取工厂
    Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
    //获取安全管理者实例
    SecurityManager sm = factory.getInstance();
    //将安全管理者放入全局对象
    SecurityUtils.setSecurityManager(sm);
    //全局对象通过安全管理者生成Subject对象
    Subject subject = SecurityUtils.getSubject();

    return subject;
}

//是否有角色
private static boolean hasRole(User user,String role) {
	Subject subject = getSubject(user);
	return subject.hasRole(role);
	}
//是否有权限
private static boolean isPermitted(User user,String permit) {
	Subject subject = getSubject(user);
	return subject.isPermitted(permit);
	}

private static boolean login(User user) {
	Subject subject = getSubject(user);
	if(subject.isAuthenticated()) {
		subject.logout();
	}
	UsernamePasswordToken token = new UsernamePasswordToken(user.getName(),user.getPassword());
	try {
		//将用户的数据token 最终传递到Realm中进行对比
		subject.login(token);	
	}catch(AuthenticationException e) {
		//e.printStackTrace();//验证错误
		return false;
	}
	
	return subject.isAuthenticated();//身份是否验证
}
}

值得改进的地方: 

1. 用户名/密码硬编码在 ini 配置文件,以后需要改成如数据库存储,且密码需要加密;
2、用户身份 Token 可能不仅仅是用户名/密码,也可能还有其他的,如登录时允许用户名/
邮箱/手机号同时登录 

 subject.isAuthenticated()  和subject.isRememebered区别

shiro 维护了这种状态,

假设你使用卓越网,你已经成功登录并且在购物蓝中添加了一些书籍,但你由于临时要参加一个会议,匆忙中你忘记退出登录,当会议结束,回家的时间到了,于是你离开了办公室。

第二天当你回到工作,你意识到你没有完成你的购买动作,于是你回到卓越网,这时,卓越网“记得”你是认证,通过你的名字向你打招呼,仍旧给你提供个性化的图书推荐,对于卓越,subject.isRemembered()将返回真。

但是当你想访问你帐号的信用卡信息完成图书购买的时候会怎样呢?虽然卓越“记住”了你(isRemembered() == true),它不能担保你就是你(也许是正在使用你计算机的同事)。

于是,在你执行像使用信用卡信息之类的敏感操作之前,卓越强制你登录以使他们担保你的身份,在你登录之后,你的身份已经被验证,对于卓越,isAuthenticated()将返回真。

这类情景经常发生,所以shiro加入了该功能,你可以在你的程序中使用。现在是使用isRemembered()还是使用isAuthenticated()来定制你的视图和工作流完全取决于你自己,但shiro维护这种状态基础以防你可能会需要。
 

猜你喜欢

转载自blog.csdn.net/qq_38930240/article/details/86606231