shrio中hashedCredentialsMatcher密碼匹配示例詳解
類圖如下:
SimpleCredentialsMatcher是明文匹配,也是shrio框架默認的比對方式,網上的例子多是此方式。實際項目中,數據庫中的密碼一般是密文,此時密碼的匹配需使用HashedCredentialsMatcher完成。
處理過程
在controller中通過Subject的login(token)將接收過來用戶賬號和密碼(明文)交給shrio框架,示例代碼如下
其次通過HashedCredentialsMatcher告訴shrio使用加密方式;
最後通過AuthorizingRealm,將數據庫中獲取的密碼,告訴shrio框架,shrio處理完成後返回處理結果。
示例代碼
數據庫創建表user,結構如下:
CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT NULL, `psw` varchar(200) DEFAULT NULL, `user_right` varchar(300) DEFAULT NULL, `create_time` date DEFAULT NULL, `salt` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`) )
在dao完成根據登錄名獲取實體對象和增加用戶兩個方法,略過。service代碼如下,保存代碼時,密碼使用sha256加密,鹽隨機獲取20位隨機數
@Service("UserService") public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService { @Override public UserEntity getUserByname(String loginName) { return baseMapper.queryByUserName(loginName); } @Override public boolean save(UserEntity user) { user.setCreateTime(new Date()); String salt = RandomStringUtils.randomAlphanumeric(20); user.setPsw(new Sha256Hash(user.getPsw(), salt).toHex());//sha256加密 user.setSalt(salt); try { baseMapper.insert(user); return true; } catch (Exception e) { return false; } } }
controller代碼如下
@RestController public class UserController { @Autowired private UserService userService; @PostMapping("/login") public Map<String, Object> login(@RequestParam Map<String, Object> params) { String username=params.get("username").toString(); String password=params.get("password").toString(); String result = "已登錄"; Subject currentUser = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, password); if (!currentUser.isAuthenticated()) { try { currentUser.login(token);// 會觸發com.shiro.config.MyShiroRealm的doGetAuthenticationInfo方法 result = "登錄成功"; } catch (UnknownAccountException e) { result = "用戶名錯誤"; } catch (IncorrectCredentialsException e) { e.printStackTrace(); result = "密碼錯誤"; } } return R.ok(result); } @GetMapping("/logout") public void logout() { Subject currentUser = SecurityUtils.getSubject(); UserEntity user = (UserEntity)currentUser.getPrincipal(); System.out.println(user.getName()); currentUser.logout(); } @RequestMapping("/user/add") public String add(@RequestBody UserEntity user) { userService.save(user); System.out.println("新增用戶"); return "hello"; } }
使用ShiroConfig 代替xml配置文件方式
@Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //設置自定義的securityManager shiroFilterFactoryBean.setSecurityManager(securityManager); //設置默認登錄的url,身份認證失敗會訪問該URL shiroFilterFactoryBean.setLoginUrl("/login"); //設置成功,會訪問該url shiroFilterFactoryBean.setSuccessUrl("/success"); //設置未授權界面,權限認證失敗會訪問該url shiroFilterFactoryBean.setUnauthorizedUrl("/notRole"); //進行攔截器配置 Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); // <!-- authc:所有url都必須認證通過才可以訪問; anon:所有url都都可以匿名訪問--> filterChainDefinitionMap.put("/webjars/**", "anon"); filterChainDefinitionMap.put("/login", "anon"); filterChainDefinitionMap.put("/", "anon"); filterChainDefinitionMap.put("/front/**", "anon"); filterChainDefinitionMap.put("/user/add", "perms[add]"); filterChainDefinitionMap.put("/admin/**", "authc"); filterChainDefinitionMap.put("/user/**", "authc"); //主要這行代碼必須放在所有權限設置的最後,不然會導致所有 url 都被攔截 剩餘的都需要認證 filterChainDefinitionMap.put("/**", "authc"); //配置logout過濾器 filterChainDefinitionMap.put("/logout","logout"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager() { DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager(); defaultSecurityManager.setRealm(customRealm()); return defaultSecurityManager; } @Bean public CustomRealm customRealm() { CustomRealm customRealm = new CustomRealm(); //SimpleCredentialsMatcher明文匹配,hashedCredentialsMatcher加鹽匹配 customRealm.setCredentialsMatcher(hashedCredentialsMatcher()); return customRealm; } @Bean public HashedCredentialsMatcher hashedCredentialsMatcher() { HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); hashedCredentialsMatcher.setHashAlgorithmName("SHA-256"); hashedCredentialsMatcher.setHashIterations(1); return hashedCredentialsMatcher; } }
Realm中代碼如下:
public class CustomRealm extends AuthorizingRealm { @Autowired private UserService userService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //授權部分代碼略 return null; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { String loginName = (String) authenticationToken.getPrincipal(); UserEntity user= userService.getUserByname(loginName); if (user == null) { // 沒找到帳號 throw new UnknownAccountException(); } // 交給AuthenticatingRealm使用CredentialsMatcher進行密碼匹配 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPsw(), ByteSource.Util.bytes(user.getSalt()),getName()); return authenticationInfo; }
測試,使用張三登錄
以上就是shrio中hashedCredentialsMatcher密碼匹配示例詳解的詳細內容,更多關於shrio中hashedCredentialsMatcher密碼匹配的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- SpringBoot 整合 Shiro 密碼登錄的實現代碼
- Java 實戰項目錘煉之在線購書商城系統的實現流程
- Spring Boot+Shiro實現一個Http請求的Basic認證
- springBoot前後端分離項目中shiro的302跳轉問題
- spring-shiro權限控制realm實戰教程