一、散列算法概述
散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据,常见的散列算法如MD5、SHA等,一般进行散列时最好提供一个salt(“盐”),什么意思?举个栗子:加密密码“admin”,产生的散列值是21232f297a57a5a743894a0e4a801fc3,可以到一些md5解密网站(注:并不是真正解密,而是通过穷举法不断尝试)很容易通过散列值得到密码(admin),即如果直接对密码进行散列相对来说破解更容易,此时我们加入一些只有系统知道的干扰数据,如用户名和ID(盐);这样散列对象是“密码+用户名+ID”,这样生成的散列值来说更难破解。
二、凭证配置
鄙人能力有限,不会叙述其是怎么实现的,有能力的可以自己去百度了。。这里仅仅记录我学习Shiro过程中通过MD5散列算法对密码进行加密,这也是Shiro框架的一部分。
1、新建module,添加如下pom依赖
<properties> <shiro.version>1.4.1</shiro.version> <loggingg.version>1.2</loggingg.version> </properties> <dependencies> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>${loggingg.version}</version> </dependency> </dependencies>
2、配置凭证
(1)第一种方式:在自定义Realm的构造方法中设置匹配器
实现如下:
关键代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class UserRealm extends AuthorizingRealm { private UserService userService = new UserServiceImpl(); private RoleService roleService = new RoleServiceImpl(); private PermissionService permissionService = new PermissionServiceImpl(); public UserRealm() { HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); //指定加密算法 hashedCredentialsMatcher.setHashAlgorithmName("md5"); //指定散列次数 hashedCredentialsMatcher.setHashIterations(2); //这里没有设置salt(盐)的api,为什么这么设计?因为一般salt(盐)存储在数据库 setCredentialsMatcher(hashedCredentialsMatcher); } /** * 做认证 * * @param token * @return * @throws AuthenticationException */ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username1 = token.getPrincipal().toString(); User user1 = userService.queryUserByUserName(username1); if (user1 != null) { List<String> roles1 = roleService.queryRoleByUserName(username1); List<String> permissions1 = permissionService.queryPermissionByUserName(username1); ActivityUser activityUser1 = new ActivityUser(user1, roles1, permissions1); System.out.println(); //参数1:可以传任意对象的|参数2:数据库中的用户密码|参数3:当前类名 //SimpleAuthenticationInfo info1 = new SimpleAuthenticationInfo(activityUser1, user1.getPwd(), this.getName()); ByteSource byteSource = ByteSource.Util.bytes("北京"); SimpleAuthenticationInfo info1 = new SimpleAuthenticationInfo(activityUser1, user1.getPwd(), byteSource, this.getName()); return info1; } else { return null; } } //授权方法 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) { SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); System.out.println("doGetAuthorizationInfo被回调了!"); // Object primaryPrincipal = principal.getPrimaryPrincipal(); System.out.println(primaryPrincipal); ActivityUser activityUser = (ActivityUser) principal.getPrimaryPrincipal(); List<String> roles = activityUser.getRoles(); if (roles != null && roles.size() > 0) { info.addRoles(roles); } List<String> permissins = activityUser.getPermissins(); if (permissins!=null&&permissins.size()>0) { info.addStringPermissions(permissins); } //判断如果是超级管理员 //info.addStringPermission("*:*"); return info; } }
(2)第2种方式:shiro.ini设置凭证匹配器
(3)第3种方式:代码中设置凭证匹配器
关键代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class TestAuthorizationRealm { public static void main(String[] args) { //1.模拟前台传递的用户名和密码 String username = "zhangsan"; String password = "123456"; //2.创建安全管理器的工厂 Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); //3.通过安全管理器工厂获取安全管理器 DefaultSecurityManager securityManager = (DefaultSecurityManager)factory.getInstance(); //4.创建自定义的Realm UserRealm userRealm = new UserRealm(); //4.1设置凭证匹配器 HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); //4.2指定加密算法 hashedCredentialsMatcher.setHashAlgorithmName("md5"); //4.3指定散列次数 hashedCredentialsMatcher.setHashIterations(2); //4.4这里没有设置salt(盐)的api,为什么这么设计?因为一般salt(盐)存储在数据库 userRealm.setCredentialsMatcher(hashedCredentialsMatcher); //5.设置自定义的Realm securityManager.setRealm(userRealm); //6.将安全管理器绑定到当前运行环境 SecurityUtils.setSecurityManager(securityManager); //7.从当前环境中获取Subject主体 Subject subject1 = SecurityUtils.getSubject(); //8.调用主体的登录方法 try { subject1.login(new UsernamePasswordToken(username,password)); System.out.println("登录成功~"); // Object principal = subject1.getPrincipal(); // System.out.println(principal); } catch (IncorrectCredentialsException e) { System.out.println("密码不正确"); }catch (UnknownAccountException e) { System.out.println("用户名不存在"); } boolean role1 = subject1.hasRole("role1"); boolean role2 = subject1.hasRole("role1"); System.out.println(role1); boolean permitted = subject1.isPermitted("user:add"); System.out.println(permitted); } }
三、总结
1、以前我们是拿用户名和密码去匹配数据库中有没有User对象,而在Shiro中是通过用户名查询User对象,将前台获取到的明文进行加密(md5、sha等等)与数据库中的密文密码作比对
2、以上3种设置凭证匹配器本质都是一样的