JavaWeb日记——当Shiro遇上Spring

在网络项目开发过程中经常要用到用户登录,还有权限管理,Shiro可以说是Spring的一把利器。

看懂这一篇博客需要两个要求

  1. 懂得SpirngMVC的基本配置和使用
  2. 懂得Shiro的基本配置和使用

先看一下项目结构


JavaWeb日记——当Shiro遇上Spring_第1张图片
项目结构

这个项目可以作为pull下来在作为一般项目的脚手架

POM


    4.0.0
    com.jk.shiroLearning
    chapter5
    war
    1.0-SNAPSHOT
    chapter5 Maven Webapp
    http://maven.apache.org

    
        2.3.0
        4.2.4.RELEASE
        3.1.0
    

    
        
            javax.servlet
            jstl
            1.2
        
        
        
            org.springframework
            spring-webmvc
            ${spring-version}
        
        
            org.springframework
            spring-context-support
            ${spring-version}
        
        
            javax.servlet
            javax.servlet-api
            ${servlet-api-version}
            provided
        
        
        
            commons-logging
            commons-logging
            1.1.3
        
        
            commons-collections
            commons-collections
            3.2.1
        
        
            org.apache.shiro
            shiro-core
            1.2.2
        
        
            org.apache.shiro
            shiro-web
            1.2.2
        
        
            org.apache.shiro
            shiro-ehcache
            1.2.2
        
        
            org.apache.shiro
            shiro-spring
            1.2.2
        
        
            mysql
            mysql-connector-java
            5.1.25
        
        
            com.alibaba
            druid
            0.2.23
        
        
    
    
        chapter5
    


首先要配置Web.xml



    
    
        contextConfigLocation
        classpath:applicationContext.xml
    

    
        org.springframework.web.context.ContextLoaderListener
    
    
    
        spring
        org.springframework.web.servlet.DispatcherServlet
        1
    

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

    
        shiroFilter
        /*
    
    

然后配置spring-servlet.xml



    
    
    
    
        
        
    
    
    
    



然后配置applicationContext.xml






    
    
        
        
        
            
                
            
        
        
    

    
    
        
    

    
        
            
        
    

    
    
        
            
                
                
            
        
        
            
                
                
                
                
            
        
        
    


    
    

    
    
    
        
    

    
    
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        

        
        

        
        
        
        
    

    
    

    

    



配置中重点讲解一下filterChainDefinitions,value对应的是url=权限或角色,具体如下

JavaWeb日记——当Shiro遇上Spring_第2张图片
身份验证相关

JavaWeb日记——当Shiro遇上Spring_第3张图片
授权相关

我们可以用一个filterChainDefinitionMap代替filterChainDefinitions

filterChainDefinitionMap

public class FilterChainDefinitionMapBuilder {

    public LinkedHashMap buildFilterChainDefinitionMap(){
        LinkedHashMap map = new LinkedHashMap();
        map.put("/login.jsp", "anon");
        map.put("/shiro/login", "anon");
        map.put("/shiro/logout", "logout");
        map.put("/role1.jsp", "authc,roles[role1]");
        map.put("/admin.jsp", "authc,roles[admin]");
        map.put("/list.jsp", "user");
        map.put("/**", "authc");
        
        return map;
    }
}

还有一点就是url的权限是先定义优先级越高,后定义的不会覆盖先定义的,可用/**匹配任何地址

然后再配置缓存



    

    
    
    

    
    

    
    
    



初始化数据库

drop database if exists shiro;
create database shiro;
use shiro;

create table users (
  id bigint auto_increment,
  username varchar(100),
  password varchar(100),
  password_salt varchar(100),
  constraint pk_users primary key(id)
) charset=utf8 ENGINE=InnoDB;
create unique index idx_users_username on users(username);

create table user_roles(
  id bigint auto_increment,
  username varchar(100),
  role_name varchar(100),
  constraint pk_user_roles primary key(id)
) charset=utf8 ENGINE=InnoDB;
create unique index idx_user_roles on user_roles(username, role_name);

create table roles_permissions(
  id bigint auto_increment,
  role_name varchar(100),
  permission varchar(100),
  constraint pk_roles_permissions primary key(id)
) charset=utf8 ENGINE=InnoDB;
create unique index idx_roles_permissions on roles_permissions(role_name, permission);

insert into users(username, password, password_salt) values('jack', 'fc1709d0a95a6be30bc5926fdb7f22f4', 'jack');
insert into user_roles(username, role_name) values('jack', 'role1');
insert into user_roles(username, role_name) values('jack', 'role2');
insert into roles_permissions(role_name, permission) values('role1', 'user1:*');
insert into roles_permissions(role_name, permission) values('role1', 'user2:*');
insert into roles_permissions(role_name, permission) values('role2', 'user3:*');

再看Controller

@Controller
@RequestMapping("/shiro")
public class ShiroController {
    
    @Autowired
    private ShiroService shiroService;
    
    @RequestMapping("/testShiroAnnotation")
    public String testShiroAnnotation(HttpSession session){
        session.setAttribute("key", "value12345");
        try {
            shiroService.testPermissionMethod();
            shiroService.testRoleMethod();
        }catch (UnauthorizedException e){
            return "redirect:/unauthorized.jsp";
        }
        return "redirect:/list.jsp";
    }

    @RequestMapping("/login")
    public String login(@RequestParam("username") String username, 
            @RequestParam("password") String password){
        Subject currentUser = SecurityUtils.getSubject();
        
        if (!currentUser.isAuthenticated()) {
            // 把用户名和密码封装为 UsernamePasswordToken 对象
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            // 记住登录
            token.setRememberMe(true);
            try {
                // 执行登录.
                currentUser.login(token);
            } 
            // 所有认证时异常的父类.
            catch (AuthenticationException ae) {
                System.out.println("登录失败: " + ae.getMessage());
            }
        }
        return "redirect:/list.jsp";
    }
    
}

可以留意到除了登录以外还有一个测试注解的方法,注解是一种比较优雅的限制执行方法权限的方法,看一下如何来使用注解

注解

public class ShiroService {

    //只需满足其中一种角色就好
    @RequiresRoles({"role1","admin"})
    public void testRoleMethod(){
        System.out.println("testMethod, time: " + new Date());
        Session session = SecurityUtils.getSubject().getSession();
        Object val = session.getAttribute("key");
        System.out.println("Service SessionVal: " + val);
    }

    //只需满足其中一种权限就好
    @RequiresPermissions({"user1:*","user4:*"})
    public void testPermissionMethod(){
        System.out.println("testMethod, time: " + new Date());
        Session session = SecurityUtils.getSubject().getSession();
        Object val = session.getAttribute("key");
        System.out.println("Service SessionVal: " + val);
    }

}

Shiro还为我们提供了SecurityUtils.getSubject().getSession()的方法来获取Session,这样就不用传requset到方法里。

Shiro还有我们提供了标签

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>    
    




Insert title here


    

List Page

欢迎游客访问 已登录 已通过认证 未通过身份认证(包括记住我) 拥有角色admin 拥有角色admin或role1 不拥有角色admin Welcome:

guest 标签:用户没有身份验证时显示相应信息,即游客访问信息:
user 标签:用户已经经过认证/记住我登录后显示相应的信息。
authenticated 标签:用户已经身份验证通过,即Subject.login登录成功,不是记住我登录的
notAuthenticated 标签:用户未进行身份验证,即没有调用Subject.login进行登录,包括记住我自动登录的也属于未进行身份验证。
pincipal 标签:显示用户身份信息,默认调用Subject.getPrincipal() 获取,即 Primary Principal。
hasRole 标签:如果当前 Subject 有角色将显示 body 体内容:Shiro 标签
hasAnyRoles 标签:如果当前Subject有任意一个角色(或的关系)将显示body体内容。

Shiro对一些角色和复杂的项目简直就是福音,对spring的支持也是十分友好,配置起来十分的简单

源码地址:https://github.com/jkgeekJack/shiro-learning/tree/master/chapter5

你可能感兴趣的:(JavaWeb日记——当Shiro遇上Spring)