30分钟了解Shiro与Springboot的多Realm基础配置

写在前面的话:spring

我以前写过两篇与shiro安全框架有关的博文,竟然可以广受欢迎实在使人意外。说明你们在互联网时代大伙对于安全和登陆都很是重视,不管是大型项目仍是中小型业务,广泛都至少须要登陆与认证的逻辑封装。相较于SpringSecurity而言,Shrio更轻量无过多依赖和便于独立部署的特色更收到开发者的欢迎。本篇博客只做为前两篇对于shiro使用的基础补充,我只谈谈如何在springboot项目中配置多角色验证。数据库

1、场景介绍安全

假设在咱们的项目中须要有前台用户登陆和后台系统管理员登陆两种验证方式。固然在传统的业务逻辑中用户和管理员可使用不一样的角色加以区分,假设如今的逻辑是用户与系统管理员分别保存在不一样的表中而且也分别对应了不一样的角色(role)与权限(permission)。换句话说,从业务上看相同的用户名和密码若是是在前台页面登陆可能对应的是普通用户,从后台登陆则对应某板块的系统管理。面对这样的需求咱们能够在shiro框架中配置多个realm,再配合上认证策略来执行。springboot

2、代码讲解框架

与单一realm相同,首先根据不一样的登陆认证要求建立不一样的realm。这里只提供做为后台系统管理员的realm代码实例:dom

// 系统管理员专用
public class AdministratorRealm extends AuthorizingRealm {
    @Autowired
    private AdministratorRegisterService administratorRegisterService;
    @Autowired
    private PasswordSupport passwordSupport;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        String username = (String) principals.getPrimaryPrincipal();
        Administrator administrator = administratorRegisterService.getAdministratorByName(username);
        for (Role r : administrator.getRoles()) {
            authorizationInfo.addRole(r.getRoleName());
        }
        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();
        Administrator administrator = administratorRegisterService.getAdministratorByName(username);
        if (administrator == null) {
            throw new UnknownAccountException();
        }
        if (administrator.isLocked()) {
            throw new LockedAccountException();
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(administrator.getUsername(),
                administrator.getPassword(), ByteSource.Util.bytes(passwordSupport.credentialsSalt(administrator)),
                getName());

        return authenticationInfo;
    }

}

doGetAuthenticationInfo方法负责用户名和密码验证,doGetAuthorizationInfo方法负责角色和权限的分配, passwordSupport是一个自定义的类负责password加密和生成salt功能。ide

/**
 * 密码辅助方法
 * 
 * @author learnhow
 *
 */
@Component
public class PasswordSupport {
    public static final String ALGORITHM_NAME = "md5";
    public static final int HASH_ITERATIONS = 2;/**
     * 针对系统管理生成salt和加密密码
     * 
     * @param administrator
     */
    public void encryptPassword(Administrator administrator) {
        administrator.setSalt(new SecureRandomNumberGenerator().nextBytes().toHex());
        String newPassword = new SimpleHash(ALGORITHM_NAME, administrator.getPassword(),
                ByteSource.Util.bytes(credentialsSalt(administrator)), HASH_ITERATIONS).toHex();
        administrator.setPassword(newPassword);
    }/**
     * 对Administrator的salt生成规则
     * 
     * @param administrator
     * @return
     */
    public String credentialsSalt(Administrator administrator) {
        return administrator.getSalt() + administrator.getEmail();
    }
}

AdministratorRegisterService是服务组件负责经过name从数据库中查询。加密

在Shiro中不管是单一realm仍是多个realm都须要对SecurityManager进行配置。spa

@Configuration
public class ShiroConfig {
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName(PasswordSupport.ALGORITHM_NAME);
        hashedCredentialsMatcher.setHashIterations(PasswordSupport.HASH_ITERATIONS);
        return hashedCredentialsMatcher;
    }

    @Bean
    public AdministratorRealm getAdministatorRealm() {
        AdministratorRealm realm = new AdministratorRealm();
        realm.setName("AdministratorRealm");
        realm.setCredentialsMatcher(hashedCredentialsMatcher());
        return realm;
    }

    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        ModularRealmAuthenticator modularRealmAuthenticator = new ModularRealmAuthenticator();
        modularRealmAuthenticator.setAuthenticationStrategy(new FirstSuccessfulStrategy());
        securityManager.setAuthenticator(modularRealmAuthenticator);

        List<Realm> realms = new ArrayList<>();
        // TODO-多个realms进配置在这里 
        realms.add(getAdministatorRealm());
        securityManager.setRealms(realms);
        return securityManager;
    }
}

ModularRealmAuthenticator的setAuthenticationStrategy方法中配置认证策略。Shiro提供了三种策略:AllSuccessFulStrategy, AtLeastOneSuccessFulAtrategy, FirstSuccessFulStrategy,默认使用AtLeastOneSuccessFulAtrategy,一般不须要特别配置。code

3、注意事项

1.多realm认证只会抛出AuthenticationException,所以若是要想在外部判断究竟是在认证的哪一步发生的错误须要本身定义一些异常类型。

2.shiro没有提供根据条件指定realm的功能,若是须要实现这样的功能只能经过继承与重写来实现,这里没有涉及须要深刻探讨的同窗最好根据本身的实际状况专门研究。

 

写在后面的话:

最近有很多朋友在看了个人博客之后加个人QQ或者发邮件要求提供演示源码,为了方便交流我索性建了一个技术交流群,从此有些源码我可能就放群资料里面了。固然以前的一些东西还在补充中,有些问题也但愿大伙能共同交流。QQ群号:960652410

相关文章
相关标签/搜索