使用shiro结合spring框架进行用户认证

Apache Shiro 是 Java 的一个安全框架。目前,使用 Apache Shiro 的人越来越多,因为它相当简单,对比 Spring Security,可能没有 Spring Security 做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的 Shiro 就足够了。

HP-shiro-spring是一个简单的基于Spring实现shiro的例子,进行用户的身份认证,实现基于role的授权。该项目是由MyEclipse进行构建的动态web项目。

项目具体实现层次结构如下:


使用shiro结合spring框架进行用户认证_第1张图片
HP-shiro-spring-test.png
  1. 首先定义shiro.ini,用来指定用户身份和凭据。
[users]
root = secret, root
guest = guest, guest
gandhi = 12345, role1, role2
bose = 67890, role2

[roles]
root = *
role1 = filesystem:*,system:*
role2 = "calculator:add,subtract"

上面的shiro.ini文件定义了四个用户,格式为“用户名=密码,角色”;每个角色拥有一些权限。
root拥有所有的权限,role1拥有filesystem以及system的所有权限,role2拥有calculator的add和substract权限。这些权限在当前用户对系统资源进行访问的时候要用到。

2.定义配置文件
web.xml



    
    
        org.springframework.web.context.ContextLoaderListener
    
    
    
    
    
        org.apache.shiro.web.env.EnvironmentLoaderListener
        

    
    
        shiroFilter
        org.springframework.web.filter.DelegatingFilterProxy
        
            targetFilterLifecycle
            true
        
    

    
    
        shiroFilter
        /*
        REQUEST 
        FORWARD 
        INCLUDE 
        ERROR        
    
    
    
    
        springMvc
        org.springframework.web.servlet.DispatcherServlet
        1
    
    
    
    
    
        springMvc
        /
    
    

    
        index.jsp
    


springMvc-servlet.xml



    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
        
            
                
                    
                        
                            text/plain;charset=UTF-8
                        
                    
                
            
        
    
    
    
    
         
    
    
        
        
    
    
    


applicationContext.xml



    
    
        
    

    
        
    
     
    

    
    
    
        
    
    
    
        
        
        

        
            
                /home/** = authc
            
        
    



3.然后定义ProtectedService.java来实现功能。

package com.hp.shiro.simplerbac.bean;

import java.io.File;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.shiro.authz.annotation.RequiresPermissions;

public class ProtectedService {
    private static final List USERS = Arrays.asList("root","guest","gandhi","bose");
    
    private static final List ROLES = Arrays.asList("root","guest","role1","role2");
    
    @RequiresPermissions("user-roles:read")
    public List getUsers() {
        return USERS;
    }
    
    @RequiresPermissions("user-roles:read")
    public List getRoles() {
        return ROLES;
    }
    
    @RequiresPermissions("system:read:time")
    public Date getSystemTime() {
        return Calendar.getInstance().getTime();
    }
    
    @RequiresPermissions("calculator:add")
    public int sum(int a, int b) {
        return a+b;
    }
    
    @RequiresPermissions("calculator:subtract")
    public int diff(int a, int b) {
        return a-b;
    }
    
    @RequiresPermissions("filesystem:read:home")
    public List getHomeFiles() {
        File homeDir = new File(System.getProperty("user.home"));
        return Arrays.asList(homeDir.list());
    }

    public String getGreetingMessage(String name) {
        return String.format("Hello %s",name);
    }
}

使用了@RequiresPermissions()注解来表示每一个方法的需要的permission,没有该注解的getGreetingMessage(String name)方法不要求任何权限。

4.定义两个Controller,分别是登陆/登出页面的controller和成功登陆以后完成访问系统资源功能的controller。

package com.hp.shiro.simplerbac.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;


@Controller
public class LoginController {
    @RequestMapping(value="login", method=RequestMethod.GET)
    public String login(HttpServletRequest req){
        if (SecurityUtils.getSubject().isAuthenticated()) {
            return "redirect:/home";
        } else {
            return "login";
        }
    }

    @RequestMapping(value="login", method=RequestMethod.POST)
    public String login(HttpServletRequest req,RedirectAttributes redirectAttributes,Model model) {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println("access to login");
        System.out.println(username+","+password);
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        String errorMessage = null;
        try {
            SecurityUtils.getSubject().login(token);
        } catch (AuthenticationException e) {
            errorMessage = "user name doesn't exist or wrong password";
        }
        if(null == errorMessage) {
            redirectAttributes.addAttribute("username", username);
            return "redirect:/home";
        } else {
            System.out.println(errorMessage);
            req.setAttribute("errorMessage",errorMessage);
            return "login";
        }
    }
    
    @RequestMapping(value="logout")
    public String logout(HttpServletRequest req){
        SecurityUtils.getSubject().logout();
        return "redirect:/login";
    }
    
    
}

package com.hp.shiro.simplerbac.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.hp.shiro.simplerbac.bean.ProtectedService;

@Controller
public class HomeController {
    @RequestMapping(value="home")
    public String home(HttpServletRequest req, HttpServletResponse response, Model model){
//      System.out.println("access to home controller.");
        String username = (String)SecurityUtils.getSubject().getPrincipal();
//      System.out.println("username:"+username);
        model.addAttribute("username", username);
        String method = req.getParameter("method");
//      System.out.println("method:"+method);
        /*
         * method可能的值value包括:
         *  
         *  
         *  
         *  
         *  
         *  
         *  
         */

        ProtectedService protectedService = new ProtectedService();
        
        try {
            if ("getUsers".equals(method)) {
                model.addAttribute("users", protectedService.getUsers());
            } else if ("getRoles".equals(method)) {
                model.addAttribute("roles", protectedService.getRoles());
            } else if ("getSystemTime".equals(method)) {
                model.addAttribute("systemTime", protectedService.getSystemTime());
            } else if ("sum".equals(method)) {
                int a = Integer.parseInt(req.getParameter("a"));
                int b = Integer.parseInt(req.getParameter("b"));
                model.addAttribute("sum",protectedService.sum(a, b));
            } else if ("diff".equals(method)) {
                int a = Integer.parseInt(req.getParameter("a"));
                int b = Integer.parseInt(req.getParameter("b"));
                model.addAttribute("diff",protectedService.diff(a, b));
            } else if ("getHomeFiles".equals(method)) {
                model.addAttribute("homeFiles",protectedService.getHomeFiles());
            } else if ("getGreetingMessage".equals(method)) {
                String name = req.getParameter("name");
                model.addAttribute("greetingMessage",protectedService.getGreetingMessage(name));
            }
        } catch(Exception e) {
            model.addAttribute("errorMessage", e.getMessage());
        }
        
        return "home";
    }
}

5.定义jsp文件和css样式文件,具体代码参见工程源码HP-shiro-spring

总结:
该项目的主要目的是对spring的shiro的配置文件进行一个梳理,了解它俩结合的具体配置方式。
该项目将用户名和密码简单的存放在文本文件中,而且是明文存储,以后需要迁移到数据库加密存储的形式。
参考开涛的博客进一步对shiro的功能进行探索。例如加密解密模块和session管理模块。

2016/06/22日更新:使用shiro+springmvc+mybatis实现的小例子,页面没有变化,添加了数据库的支持。
项目地址:https://github.com/lunabird/shiro-demo.git

你可能感兴趣的:(使用shiro结合spring框架进行用户认证)