shiro认证管理
1、认证
身份认证就是判断一个用户是否为合法用户的处理过程。通过核对用户输入的用户名和口令,判断身份是否正确。
2、shiro中认证关键对象
subject:主体
访问系统的用户,主体可以是用户、程序等,进行认证都称为主体。
Principal:身份信息
例如:是主体(subject)进行身份认证的标识,标识必须具有唯一性。一个主体可以有多个身份,例如可以用手机号、账号、邮箱进行账号密码登陆。
Credential:凭证信息
口令,只有主体自己知道的安全信息,例如,密码,证书等。
3、认证流程
登陆用户,携带身份和口令(凭证),将两种信息打包成一个令牌,shirofilter进行拦截,将令牌拿到安全管理器中,调用认证器,认证器调用reaml获取数据库中数据,如果身份信息与口令与原始数据中的存留信息一致,就属于认证成功,放行进入系统,否则失败。
4、认证开发
4.1 引入依赖
<!--编码处理 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<!--JDk版本的引入 -->
<profiles>
<profile>
<id>development</id>
<activation>
<jdk>1.8</jdk>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
</profiles>
<!--shiro包引入 -->
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.5.3</version>
</dependency>
</dependencies>
4.2 shiro.ini配置文件
在resource目录下,该配置存放的本次认证的账号和密码。
[users] zhangsan=123 lisi=456 wangwu=789
4.3 认证代码
package com.demo; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.realm.text.IniRealm; import org.apache.shiro.subject.Subject; public class ShiroDemo { public static void main(String[] args) { //创建安全管理器 DefaultSecurityManager defaultSecurityManager=new DefaultSecurityManager(); //创建realm 读取配置文件中的用户名 密码 defaultSecurityManager.setRealm(new IniRealm("classpath:shiro.ini")); //使用工具,将安装工具类中设置默认安全管理器 SecurityUtils.setSecurityManager(defaultSecurityManager); //实用工具类获取登录主体 Subject subject = SecurityUtils.getSubject(); //创建令牌 用户名+密码 UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "123"); try { System.out.println("认证状态:"+subject.isAuthenticated()); subject.login(token);//用户登录 这里加入了用户登陆信息 System.out.println("认证状态:"+subject.isAuthenticated()); //验证登陆信息 System.out.println("登录成功!!"); } catch (UnknownAccountException e) { e.printStackTrace(); System.out.println("用户名错误!!"); }catch (IncorrectCredentialsException e){ e.printStackTrace(); System.out.println("密码错误!!!"); } } }
其他认证异常
DisabledAccountException(账号被禁用)
LockedAccountException(账号被锁定)
ExcessiveAttemptsException(登录失败次数过多)
ExpiredCredentialsException(凭证过期)
5、加盐认证
md5工具,加入不同字符串数字后密码的强度
package com.demo.md5; import org.apache.shiro.crypto.hash.Md5Hash; /** * 三种组合的md5加密 * @author Administrator * */ public class ShiroMD5 { public static void main(String[] args) { Md5Hash md5Hash=new Md5Hash("123"); //这个容易被反编译 安全性不高 System.out.println(md5Hash.toHex()); //md5+salt md5加密+自定义字符串 Md5Hash md5Hash2=new Md5Hash("123","x0*&p"); System.out.println(md5Hash2.toHex()); //md5+salt+hash散列 Md5Hash md5Hash3=new Md5Hash("123","x0*&p",1024); System.out.println(md5Hash3.toHex()); } }
效果:
202cb962ac59075b964b07152d234b70
0ea1434575ac41da89b2335d8dde11e1
efe2cdcad63be25838e3847becd43df4
自定义CustomerRealm类中,需要继承AuthorizingRealm类,进行登陆账号、密码、盐salt的定义,当然真实情况,账号密码应该从数据库中获取。salt应该作为随机字符串变量存在。
package com.demo.md5; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.ByteSource; /** * 自定义md5+salt realm */ public class CustomerRealm extends AuthorizingRealm { //授权方法 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { return null; } //认证方法 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //获取身份信息 String principal = (String) token.getPrincipal(); //这里的zhangsan就是数据查出来的,模拟 这里的账号、密码按道理是在数据库的变量 if("zhangsan".equals(principal)){ String password = "efe2cdcad63be25838e3847becd43df4"; String salt = "x0*&p"; //自定义加盐 //数据库的用户名 //数据库md5+salt之后的密码 //注册时的随机盐 //realm的名字 return new SimpleAuthenticationInfo(principal,password, ByteSource.Util.bytes(salt),this.getName()); } return null; } }
测试类
package com.demo.md5; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.subject.Subject; public class TestAuthenticatorCusttomerRealm { public static void main(String[] args) { //创建securityManager DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); //IniRealm realm = new IniRealm("classpath:shiro.ini"); //设置为自定义realm获取认证数据 CustomerRealm customerRealm = new CustomerRealm(); //设置md5加密 HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); credentialsMatcher.setHashAlgorithmName("MD5"); //添加加密字符串 credentialsMatcher.setHashIterations(1024);//设置散列次数 打乱顺序 customerRealm.setCredentialsMatcher(credentialsMatcher); //在customerRealm设置加密后的密码验证器//设置自定义realm defaultSecurityManager.setRealm(customerRealm); //将自定义的realm设置到安全管理中 //将安装工具类中设置默认安全管理器 SecurityUtils.setSecurityManager(defaultSecurityManager); //将安全管理设置到安全工具中 //获取主体对象 Subject subject = SecurityUtils.getSubject(); //创建token令牌 UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "123"); try { //subject对象 中方法 +加盐 +验证+权限操作 subject.login(token);//用户登录,shiro会自动将token中的password在自定义realm中加上盐去处理 System.out.println("登录成功~~"); } catch (UnknownAccountException e) { e.printStackTrace(); System.out.println("用户名错误!!"); }catch (IncorrectCredentialsException e){ e.printStackTrace(); System.out.println("密码错误!!!"); } } }
6、授权认证
CustomerRealm类中添加可放通的角色role,添加可访问资源"user:*:01"。
package com.demo.grant; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.ByteSource; //授权领域 public class CustomerRealm extends AuthorizingRealm { //授权方法 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //获取主要身份 String primaryPrincipal = (String) principals.getPrimaryPrincipal(); System.out.println("primaryPrincipal = " + primaryPrincipal); //根据身份信息 用户名 获取当前用户的角色信息,以及权限信息 xiaochen admin user SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); //将模拟数据库中查询角色信息赋值给权限对象 simpleAuthorizationInfo.addRole("admin"); simpleAuthorizationInfo.addRole("user"); //将数据库中查询权限信息赋值给权限对象 //对用户下01实例具有所有权限 这是资源路径实例 simpleAuthorizationInfo.addStringPermission("user:*:01"); //对product下一切资源实例具有创建权限,*可以省略 simpleAuthorizationInfo.addStringPermission("product:create"); return simpleAuthorizationInfo; } //认证方法 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String principal = (String) token.getPrincipal(); if("zhangsan".equals(principal)){
//模拟数据库中已经md5加盐处理过的密码 String password = "efe2cdcad63be25838e3847becd43df4"; String salt = "x0*&p"; //需要这个解开密码 return new SimpleAuthenticationInfo(principal,password, ByteSource.Util.bytes(salt),this.getName()); } return null; } }
测试类
package com.demo.md5; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.subject.Subject; public class TestAuthenticatorCusttomerRealm { public static void main(String[] args) { //创建securityManager DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); //IniRealm realm = new IniRealm("classpath:shiro.ini"); //设置为自定义realm获取认证数据 CustomerRealm customerRealm = new CustomerRealm(); //设置md5加密 HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); credentialsMatcher.setHashAlgorithmName("MD5"); //添加加密字符串 credentialsMatcher.setHashIterations(1024);//设置散列次数 打乱顺序 customerRealm.setCredentialsMatcher(credentialsMatcher); //MD5加密器//设置自定义realm defaultSecurityManager.setRealm(customerRealm); //将自定义的realm设置到安全管理中 //将安装工具类中设置默认安全管理器 SecurityUtils.setSecurityManager(defaultSecurityManager); //将安全管理设置到安全工具中 //获取主体对象 Subject subject = SecurityUtils.getSubject(); //创建token令牌 UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "123"); try { //subject对象 中方法 +加盐 +验证+权限操作 主体对象调用login方法 subject.login(token);//用户登录,shiro会自动将token中的password在自定义realm中加上盐去处理 System.out.println("登录成功~~"); } catch (UnknownAccountException e) { e.printStackTrace(); System.out.println("用户名错误!!"); }catch (IncorrectCredentialsException e){ e.printStackTrace(); System.out.println("密码错误!!!"); } } }