java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > shrio中hashedCredentialsMatcher密码匹配

shrio中hashedCredentialsMatcher密码匹配示例详解

作者:guoyp2126

shrio是一个轻量级权限管理框架,密码的匹配由框架内部完成。密码是否匹配由接口CredentialsMatcher定义实现类完成,CredentialsMatcher实现类有SimpleCredentialsMatcher和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密码匹配的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文