SpringBoot整合shiro的一个完整的小案例

SpringBoot整合配置版的shiro很简单,逻辑清
首先在pom.xml的配置如下,shiro使用缓存ehcache

        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>2.10.4</version>
        </dependency>
        <!-- shiro spring. -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.2.2</version>
        </dependency>
        <!-- shiro ehcache -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.2.2</version>
        </dependency>

接着配置shiro

@Configuration
public class ShiroConfig {

    @Bean  
    public ShiroFilterFactoryBean shirFilter(DefaultWebSecurityManager securityManager) {  

        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();  
        // 必须设置 SecurityManager  
        shiroFilter.setSecurityManager(securityManager);  
        // 拦截器  
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();  
        // 设置login URL  
        shiroFilter.setLoginUrl("/login");  
        // 登录成功后要跳转的链接  
        shiroFilter.setSuccessUrl("/main");  
        filterChainDefinitionMap.put("/webjars/**", "anon");
        filterChainDefinitionMap.put("/druid/**", "anon");
        //静态资源的处理
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/asserts/**", "anon");
        filterChainDefinitionMap.put("/fonts/**", "anon");
        filterChainDefinitionMap.put("/images/**", "anon");

        // 退出系统的过滤器  
        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/login", "anon"); 

        filterChainDefinitionMap.put("/kaptcha", "anon");

        filterChainDefinitionMap.put("/**", "authc");  
        shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMap);  
        return shiroFilter;  
    }  

    @Bean  
    public HashedCredentialsMatcher hashedCredentialsMatcher() {  
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();  
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        hashedCredentialsMatcher.setHashIterations(1024);
        return hashedCredentialsMatcher;  
    }  

    @Bean
    public ShiroRealm shiroRealm(HashedCredentialsMatcher hashedCredentialsMatcher) {
        ShiroRealm shiroRealm = new ShiroRealm();
        shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher);
        return shiroRealm;
    }
    //shiro使用缓存ehcachae
    @Bean
    public EhCacheManager ehCacheManager() {
        EhCacheManager ehCacheManager = new EhCacheManager();
        ehCacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
        return ehCacheManager;

    }

    @Bean("sessionManager")
    public SessionManager sessionManager(){
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionValidationSchedulerEnabled(true);
        sessionManager.setSessionIdCookieEnabled(true);
        return sessionManager;
    }

    @Bean("securityManager")
    public DefaultWebSecurityManager securityManager(ShiroRealm shiroRealm, SessionManager sessionManager) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(shiroRealm);
        securityManager.setSessionManager(sessionManager);

        return securityManager;
    }

    @Bean("lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
        proxyCreator.setProxyTargetClass(true);
        return proxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }
}

在配置中提到的realm如下配置


public class ShiroRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        // 取出表单用户名
        String username = upToken.getUsername();
        // 查询是否有该用户
        if (userService.getByName(username) == null) {
            throw new UnknownAccountException("用户不存在!");
        }
        // 靠用户名从数据库查询该用户的全部信息
        User user = userService.getByName(username);
        // 传入:用户名,加密后的密码,盐值,该realm的名字,加密算法和加密次数在已经在配置文件中指定
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, user.getPassword(),
                ByteSource.Util.bytes(username), getName());
        return info;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // 1. 从 PrincipalCollection 中来获取登录用户的信息
        Object principal = principals.getPrimaryPrincipal();
        // 2. 利用登录的用户的信息来..当前用户的角色或权限(可能需要查询数据库)
        Set<String> roles = new HashSet<String>();
        roles.add("user");
        if ("admin".equals(principal)) {
            roles.add("admin");
        }
        // 3. 创建 SimpleAuthorizationInfo, 并设置其 reles 属性
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
        // 4. 返回 SimpleAuthorizationInfo 对象.
        return info;
    }

}

由于我做的平台只有一个管理员就不写注册了,这时手动算出一个admin用户的密码

    public static void main(String[] args) {

        Object result = new SimpleHash("MD5","123456",ByteSource.Util.bytes("admin"),1024);
        System.out.println(result);
    }

最后写登录的Controller

@Controller
public class LoginController {
    // 处理登录逻辑
    @PostMapping("/login")
    public String login(String username, String password, String kaptcha, HttpSession session,
            Map<String, Object> map) {
        Subject currentUser = SecurityUtils.getSubject();
        if (!currentUser.isAuthenticated()) {
            // 把用户名和密码封装为 UsernamePasswordToken 对象
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            // 设置为rememberme
            token.setRememberMe(true);
            try {
                // 执行登录.
                currentUser.login(token);
            }
            // 所有认证时异常的父类
            catch (AuthenticationException ae) {
                map.put("password", "输入的用户名或密码错误");
                log.info("登录失败: " + ae.getMessage());
                return "login";
            }
        }
        if (!session.getAttribute("code").equals(kaptcha)) {
            map.put("kaptcha", "输入的验证码错误");
            return "login";
        }

        session.setAttribute("loginUser", "user");
        return "main";

    }

}

猜你喜欢

转载自blog.csdn.net/lhc0512/article/details/79887384