当前位置: 代码迷 >> 综合 >> shiro(二)身份验证 基于ini文件
  详细解决方案

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

热度:84   发布时间:2023-12-29 17:04:38.0

简单的身份验证 

  • 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,adminli4=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());elseSystem.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);elseSystem.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);}elseSystem.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维护这种状态基础以防你可能会需要。
 

  相关解决方案