在上一章已经搭建了Web环境,模拟了登录退出的场景,现在我们使用shiro框架来做登录管理

  在pom.xml中添加spring-shiro依赖

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.0</version>
</dependency>
pom.xml

  Shiro 中的Realm 作用相当与数据源,AuthorizingRealm 的功能是提供用户验证信息和用户权限信息。在这里我们继承AuthorizingRealm 实现doGetAuthenticationInfo方法,登录用户是“admin”时,这创建SimpleAuthenticationInfo返回。SimpleAuthenticationInfo 中要包含对应的验证字段,Shiro会将SimpleAuthenticationInfo和登录请求参数做对比,如果没有匹配登录失败,如果方法返回空也同样登录失败。

public class MyShiroRealm extends AuthorizingRealm {
    /**
     * 用于判断登录信息的方法
     */
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken authcToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        String name = token.getUsername();
        //String password = String.valueOf(token.getPassword());
        if ("admin".equals(name)) {
            return new SimpleAuthenticationInfo(name, "123456", getName());
        } else {
            return null;
        }
    }
    /**
     * 这里是用来返回用户权限的方法
     */
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
}
MyShiroRealm.java

  Shiro 在Web中是以filter的模式工作的,在Shiro中主要的验证判断是交给SecurityManager  完成的,所以我们需要创建SecurityManager 并将自定义的Realm 配置进去,然后将SecurityManager  配置到ShiroFilterFactoryBean 中。

  再说ShiroFilterFactoryBean 这个类会对应我们配置的参数生成filter,对匹配的url进行拦截判断

@Configuration
public class ShiroConfig {

    /**
     * Shiro 的使用中只有一个SecurityManager,用于管理所有的安全操作
     * 这里生成SecurityManager 并配置Realm
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(new MyShiroRealm());
        return securityManager;
    }
    /**
     * 这个方法生成ShiroFilter的工厂类,因为Shiro要起作用,就需要配置到Spring的过滤器链中。
     * 这样shiro就会拦截到请求进行处理
     */
    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //拦截器.
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        //配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
        filterChainDefinitionMap.put("/logout", "logout");

        //配置静态资源放行
        filterChainDefinitionMap.put("/favicon.ico", "anon");
        filterChainDefinitionMap.put("/static/**", "anon");
        //<!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
        //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
        filterChainDefinitionMap.put("/**", "authc");
        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/index");
        //未授权界面;
        //shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }
}
ShiroConfig.java

  现在我们的登录已经交给Shiro管理了,所有需要修改我们的Controller了,首先/logout不需要了,其次在登录成功之后,浏览器会持有对应的Cookie,所以如果登录了就不需要在进入login页面了,最后如果登录成功Shiro会直接转跳到登录成功的url,如果等失败会继续执行我们的登录函数,这时可以从request 中获取到shiro发现的异常类型。

@Controller
public class HomeController {
    @RequestMapping(value = {"/", "/index"}, method = RequestMethod.GET)
    public String index() {
        return "index";
    }
    /**
     * 如果已经登录了,直接转跳index
     */
    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String loginGet(Model model) {
        if (ShiroUtils.getSubject().isAuthenticated()) {
            return "redirect:index";
        } else {
            model.addAttribute("msg", "请登录");
            return "login";
        }
    }
    /**
     * 登录成功会直接按配置转跳
     * 登录失败的时候会进入到这个函数里,可以提取出登录报错
     */
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public String loginPost(HttpServletRequest request, Model model) {
        Object exception = request.getAttribute("shiroLoginFailure");
        String msg = "登录失败";
        if (exception != null) {
            if (UnknownAccountException.class.getName().equals(exception)) {
                msg = "用户名不正确,请重新输入";
            } else if (IncorrectCredentialsException.class.getName().equals(exception)) {
                msg = "密码错误,请重新输入";
            } else {
                msg = "发生未知错误,请联系管理员。";
            }
        }
        model.addAttribute("msg", msg);
        return "login";
    }
}
HomeController.java

 源码地址:https://github.com/StarkTan/SpringBootShiro

posted on 2018-09-08 10:59  Stark_Tan  阅读(636)  评论(0编辑  收藏  举报