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其它相關文章!

推薦閱讀: