springboot和shiro的整合

直接贴上代码

1. 所需要的jar包

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.4.0</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>1.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.4.0</version>
        </dependency>

2. 所需要的Configuration

/**
 * Shiro的配置文件
 */
@Configuration
public class ShiroConfig {
    /**
     * 自定义Realm,可以多个
     */
    @Bean
    public ShiroRealm myRealm(){
        ShiroRealm shiroRealm = new ShiroRealm();
        return shiroRealm;
    }
    @Bean
    public SessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        // 设置session过期时间为30分钟
        sessionManager.setGlobalSessionTimeout(30 * 60 * 1000);
        // 设置定时器,检查session时候国企
        sessionManager.setSessionValidationSchedulerEnabled(true);
        // 去掉shiro登录时url里的JSESSIONID
        sessionManager.setSessionIdUrlRewritingEnabled(false);
        return sessionManager;
    }

    /**
     * SecurityManager 安全管理器;Shiro的核心
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        //将session设置到SecurityManager中
        manager.setSessionManager(sessionManager());
        //将realm设置到SecurityManager中
        manager.setRealm(myRealm());
        return manager;
    }

    /**
     * shiroFilter过滤类
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(securityManager());
        bean.setLoginUrl("/");           // 登录的路径
        bean.setSuccessUrl("/success"); // 登录成功后跳转的路径
        bean.setUnauthorizedUrl("/403"); // 验证失败后跳转的路径
        Map<String, String> map = new LinkedHashMap<>();

        map.put("/captcha", "anon");
        map.put("/captcha.jpg", "anon");
        map.put("/statics/**", "anon");
        map.put("/login.html", "anon");
        map.put("/favicon.ico", "anon");
        map.put("/login", "anon");
        map.put("/**", "authc");
        map.put("/logout", "logout");
        bean.setFilterChainDefinitionMap(map);
        return bean;
    }

    /**
     * 配置Shiro生命周期处理器
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 自动创建代理类,若不添加,Shiro的注解可能不会生效。
     */
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    /**
     * 开启Shiro的注解
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }
    /**
     * 配置加密匹配,使用MD5的方式,进行1024次加密
     */
//    @Bean
//    public HashedCredentialsMatcher hashedCredentialsMatcher() {
//        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//        hashedCredentialsMatcher.setHashAlgorithmName("des");
//        hashedCredentialsMatcher.setHashIterations(1024);
//        return hashedCredentialsMatcher;
//    }
}

3.重写realm

public class ShiroRealm extends AuthorizingRealm {
    @Autowired
    private LoginDao loginDao;

    // 验证权限(登录的时候使用的)
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username = token.getUsername();
        UserDO userDO = loginDao.selectOne(new QueryWrapper<UserDO>().eq("username", username));
        if (userDO == null) {
            throw new UnknownAccountException("未知账号");//没找到帐号
        }
        // 交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配
        //使用 ByteSource.Util.bytes() 来计算盐值.
        return new SimpleAuthenticationInfo(userDO, userDO.getPassword(),ByteSource.Util.bytes(userDO.getPassword()), getName());
    }

    // 添加权限
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    /**
     * 设定Password校验
     */
    @PostConstruct
    public void initCredentialsMatcher() {
        //重写shiro的密码验证,让shiro用我自己的验证
        setCredentialsMatcher(new CustomCredentialsMatcher());
    }
}

4. 重写密码验证类

    

public class CustomCredentialsMatcher extends SimpleCredentialsMatcher {

    /**
     * 此方法为HashedCredentialsMatcher类中真正验证密码是否一致的地方
     */
    @Override
    public boolean doCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo info) {
        // 明明authcToken跟info两个对象的里的Credentials类型都是Object,断点看到的类型都是 char[]
        // 但是 token里转成String要先强转成 char[]
        // 而info里取Credentials就可以直接使用 String.valueOf() 转成String
        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        Object tokenCredentials = encrypt(String.valueOf(token.getPassword()));
        Object infocredentials = getCredentials(info);
        return equals(tokenCredentials, infocredentials);
    }

    /**
     * 明文密码加密,将传进来密码加密方法
     */
    public String encrypt(String password) {
        //这里可以选择自己的密码验证方式 比如 md5或者sha256等
        String passwordEncrypt = password
        return passwordEncrypt;
    }
}

5. 登录的Controller

public userDO login(@RequestBody LoginRequest loginRequest) {
        try {
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken(loginRequest.getUsername(), loginRequest.getPassword());
            subject.login(token);
            System.out.println("登录成功");
        } catch (UnknownAccountException e) {
            return HttpResultUtil.error("账号不存在");
        } catch (IncorrectCredentialsException e) {
            return HttpResultUtil.error("密码错误");
        }
        catch (AuthenticationException e) {
            return HttpResultUtil.error("账户被禁用,无法登录,请联系管理员");
        }
        UserDO userDO = (UserDO) SecurityUtils.getSubject().getPrincipal();
        return userDO
}

猜你喜欢

转载自www.cnblogs.com/sjzxxy/p/11697342.html