`
lee1177
  • 浏览: 118660 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

shiro与spring配合

阅读更多

之前一直使用spring security来做安全管理,感觉配置稍微有点复杂,于是尝试了下shiro,感觉的确简单不少。记录下配置和实现过程。

因为还是spring的底子,所以用的shiro-spring,首先用maven把相关包弄下来

dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-spring</artifactId>
	<version>${shiro.version}</version>
</dependency>

 我用的版本是1.2.2

然后开始增加shiro的配置文件,xml里增加了shiro的配置引入,同时增加相应的filter

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
    	classpath*:/application-root.xml,
	classpath*:/application-shiro.xml
	</param-value>
  </context-param>
<!-- shiro security filter -->
	<filter>
	    <!-- 这里的filter-name要和spring的applicationContext-shiro.xml里的
	            org.apache.shiro.spring.web.ShiroFilterFactoryBean的bean name相同 -->
	    <filter-name>shiroFilter</filter-name>
	    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	    <init-param>
	        <param-name>targetFilterLifecycle</param-name>
	        <param-value>true</param-value>
	    </init-param>
	</filter>
	
	<filter-mapping>
	    <filter-name>shiroFilter</filter-name>
	    <url-pattern>/*</url-pattern>
	</filter-mapping>

 下面是shiro的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"
	default-lazy-init="true">

	<description>Shiro安全配置</description>

	<bean id="chainDefinitionSectionMetaSource" class="xxx.xxx.ChainDefinitionSectionMetaSource">
	    <property name="filterChainDefinitions">
	        <value>
	            /login = authc
	            /logout = logout
	            /admin/** = roles[admin]
	            /static/** = anon
	            /eventSurvey/** = anon
	            /notice/** = anon
	            /** = authc
	        </value>
	    </property>
	</bean>
	<!-- Shiro's main business-tier object for web-enabled applications -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="shiroDbRealm" />
	</bean>

	<!-- 項目自定义的Realm, 所有accountService依赖的dao都需要用depends-on声明 -->
	<bean id="shiroDbRealm" class="xxx.xxx.ShiroDbRealm">
		<property name="credentialsMatcher" ref="flameCredentialsMatcher" />
	</bean>
	<bean id="flameCredentialsMatcher" class="xxx.xxx.FlameCredentialsMatcher">
	</bean>
	<!-- Shiro Filter -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		<property name="loginUrl" value="/login" />
		<property name="successUrl" value="/" />
		<property name="unauthorizedUrl" value="/authError" />
		<property name="filters">
	        <map>
	            <entry key="authc">
	                <bean class="xxx.xxx.MyFormAuthenticationFilter"></bean>
	            </entry>
	             <entry key="roles">
	                <bean class="org.apache.shiro.web.filter.authz.RolesAuthorizationFilter"></bean>
	            </entry>
	        </map>
	    </property>
		<property name="filterChainDefinitionMap" ref="chainDefinitionSectionMetaSource" />
	</bean>
	
	<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
</beans>

 这里需要说明几个配置

1)shiro本身的过滤配置已经很好了,但我们要求可从数据库加载过滤配置,所以增加了chainDefinitionSectionMetaSource的实现,用来同时从配置文件和数据库加载过滤信息,实现如下

public class ChainDefinitionSectionMetaSource implements FactoryBean<Ini.Section>{
	@Autowired
    private ResourceDao resourceDao;

    private String filterChainDefinitions;

    public Section getObject() throws BeansException {
        //获取所有Resource
        List<Resource> list = resourceDao.findAll();

        Ini ini = new Ini();
        //加载默认的url
        ini.load(filterChainDefinitions);
        Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
        //循环Resource的url,逐个添加到section中。section就是filterChainDefinitionMap,
        //里面的键就是链接URL,值就是存在什么条件才能访问该链接
        for (Resource resource : list) {
            //如果不为空值添加到section中
            if(StringUtils.hasText(resource.getUrl()) && StringUtils.hasText(resource.getPerms())) {
                section.put(resource.getUrl(),  resource.getPerms());
            }

        }

        return section;
    }

    /**
     * 通过filterChainDefinitions对默认的url过滤定义
     * 
     * @param filterChainDefinitions 默认的url过滤定义
     */
    public void setFilterChainDefinitions(String filterChainDefinitions) {
        this.filterChainDefinitions = filterChainDefinitions;
    }

    public Class<?> getObjectType() {
        return this.getClass();
    }

    public boolean isSingleton() {
        return false;
    }
}

 这里的Resource是从数据库得到的数据,其他跟xml配置差不多,就是key-value一样的。

2)shiroDbRealm,负责根据自己的业务抓取用户信息,主要是为了安全认证用

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

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		UserInfo user = (UserInfo) principals.getPrimaryPrincipal();
		List<String> userAuths = user.getAuthList();
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		info.addRoles(userAuths);
		return info;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authcToken) throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		UserInfo user = userService.findUserById(token.getUsername());
		if (user != null) {
			String authPassword = user.getPassword();
			return new SimpleAuthenticationInfo(user,
					authPassword,getName());
		} else {
			return null;
		}
	}

}

 3)credentialsMatcher,这里是处理密码匹配用的,通常密码都是加密的,用户前台输入的密码需要自己加密算法来匹配

/**
 * 处理密码加密
 * @author lee
 *
 */
public class FlameCredentialsMatcher extends SimpleCredentialsMatcher{
	@Override  
    public boolean doCredentialsMatch(AuthenticationToken token,  
            AuthenticationInfo info) {
		String userId = token.getPrincipal().toString();
		char[] ps = (char[]) token.getCredentials();
		StringBuffer sb = new StringBuffer();
		for(char p : ps){
			sb.append(p);
		}
		String tokenMd5Pw = Encryption.encrypt(userId,sb.toString());
        return equals(tokenMd5Pw, info.getCredentials());
    }  
}

 上面的Encryption.encrypt(userId,sb.toString())是一个加密算法处理,这个可以使用shiro的加密API,也可以自己实现。info是shiroDbRealm取回的用户信息,token是前台传过来的信息。

4)对于shiro的过滤链我使用了两个简单的,一个是处理登录和权限校验的authc,一个是处理角色校验的roles,这里需要说下的是如果在filter中不增加roles,那么配置/admin/** = roles[admin]这种就不会生效。对于authc因为要做是否是ajax的验证,所以做了自己的实现封装

public class MyFormAuthenticationFilter extends FormAuthenticationFilter{
	private static final Logger log = LoggerFactory.getLogger(MyFormAuthenticationFilter.class);

	/*
	 *  主要是针对登入成功的处理方法。对于请求头是AJAX的之间返回JSON字符串。
	 */
	@Override
	protected boolean onLoginSuccess(AuthenticationToken token,
	        Subject subject, ServletRequest request, ServletResponse response)
	        throws Exception {

	    if (!isAjax(request)) {// 不是ajax请求
	        issueSuccessRedirect(request, response);
	    } else {
	    	response.setCharacterEncoding("UTF-8");
	    	response.setContentType("text/plain;charset=utf-8");
	        PrintWriter out = response.getWriter();
	        out.println("{\"success\":true,\"message\":\"登入成功\"}");
	        out.flush();
	        out.close();
	    }
	    return false;
	}

	/**
	 * 主要是处理登入失败的方法
	 */
	@Override
	protected boolean onLoginFailure(AuthenticationToken token,
	        AuthenticationException e, ServletRequest request,
	        ServletResponse response) {
	    if (!isAjax(request)) {// 不是ajax请求
	        setFailureAttribute(request, e);
	        return true;
	    }
	    try {
	        response.setCharacterEncoding("UTF-8");
	        response.setContentType("text/plain;charset=utf-8");
	        PrintWriter out = response.getWriter();
	        String message = e.getClass().getSimpleName();
	        if ("IncorrectCredentialsException".equals(message)) {
	        	out.println("{\"success\":false,\"message\":\"密码错误\"}");
	        } else if ("UnknownAccountException".equals(message)) {
	        	out.println("{\"success\":false,\"message\":\"账号不存在\"}");
	        } else if ("LockedAccountException".equals(message)) {
	        	out.println("{\"success\":false,\"message\":\"账号被锁定\"}");
	        } else {
	        	out.println("{\"success\":false,message:\"未知错误\"}");
	        }
	        out.flush();
	        out.close();
	    } catch (IOException e1) {
	        // TODO Auto-generated catch block
	        e1.printStackTrace();
	    }
	    return false;
	}

	/**
	 * 所有请求都会经过的方法。
	 */
	@Override
	protected boolean onAccessDenied(ServletRequest request,
	        ServletResponse response) throws Exception {
		log.info("权限验证");
		if (isLoginRequest(request, response)) {
            if (isLoginSubmission(request, response)) {
                if (log.isTraceEnabled()) {
                    log.trace("Login submission detected.  Attempting to execute login.");
                }
                return executeLogin(request, response);
            } else {
                if (log.isTraceEnabled()) {
                    log.trace("Login page view.");
                }
                //allow them to see the login page ;)
                return true;
            }
        } else {
            if (log.isTraceEnabled()) {
                log.trace("Attempting to access a path which requires authentication.  Forwarding to the " +
                        "Authentication url [" + getLoginUrl() + "]");
            }
            if (!isAjax(request)) {// 不是ajax请求
	            saveRequestAndRedirectToLogin(request, response);
	        } else {
	            response.setCharacterEncoding("UTF-8");
	            response.setContentType("text/plain;charset=utf-8");
	            PrintWriter out = response.getWriter();
	            out.println("{\"success\":false,\"message\":\"login\"}");
	            out.flush();
	            out.close();
	        }
            return false;
        }
	}
	private boolean isAjax(ServletRequest request){
		HttpServletRequest httpServletRequest = (HttpServletRequest) request;
		return "XMLHttpRequest".equalsIgnoreCase(httpServletRequest.getHeader("X-Requested-With"));
	}
}

 

都配置完成,shiro就跑起来了

 

分享到:
评论

相关推荐

    shiro整合spring项目实例

    通过集成Spring,我们可以使用Shiro的SessionManager和SessionDAO,配合Spring Session,实现分布式会话存储。 8. **登录与登出** Shiro 提供了简单的登录和登出API。在Controller中,我们可以调用`Subject.login...

    shiro配合sping框架

    Spring 框架如何与 Shiro 配合: 1. **集成方式**:可以通过 Spring 的 Bean 定义来配置 Shiro,或者使用 Spring Boot 的自动配置特性。 2. **依赖注入**:通过 Spring 的 DI 功能,可以将 Shiro 组件注入到 Spring ...

    Spring Boot+Apache Shiro+Spring MVC+MyBatis+Quartz+Druid DEMO

    - Shiro是一个强大的Java安全框架,提供认证、授权、加密和会话管理功能,可与Spring及其他框架无缝集成。 - 认证:处理用户身份验证,确认用户身份是否合法。 - 授权:控制已认证的用户能访问哪些资源。 - ...

    spring springmvc mybatis shiro 以及 ehcache(配合shiro实现缓存验证 配合spring实现二级缓存)

    spring springmvc mybatis shiro 以及 ehcache(配合shiro实现缓存验证 配合spring实现二级缓存) 测试 二级缓存 访问http://localhost:8080/vkblog/test/ehcacheuserlist.action 测试 访问限制 访问任意的action

    shiro的全流程demo,世界shiro在spring中认证、授权流程,自定义授权类型,分布式session、授权缓存的实现

    在本 demo 中,你将看到如何配置 Shiro 与 Spring Boot 结合,包括设置 Realm、Filter 链、SessionManager 和 CacheManager。Shiro 的 Filter 链定义了请求处理的顺序,例如 AuthenticatingFilter 用于处理认证,...

    Shiro+SpringMVC+Spring集成

    6. **测试与调试**:配合Spring的测试框架,可以编写单元测试和集成测试,确保Shiro的权限设置正确无误。 压缩包中的文件可能包含以下内容: - `spring+springmvc+shiro.doc`:这可能是详细的集成指南或者示例代码...

    spring mvc+shiro + jpa

    在"spring mvc+shiro + jpa"的权限管理示例中,这三者通常会这样配合: 1. **用户认证**:Shiro 负责用户登录验证,通过用户名和密码与数据库交互,确认用户身份。Spring MVC 提供控制器接收登录请求并调用Shiro的...

    shiro+struts2+mybatis+spring整合实例

    Spring还允许开发者进行事务管理,提供数据访问抽象,并与其他Spring模块如Spring Security(原Acegi)配合,以增强应用的安全性。 3. **Struts2**:Struts2是一个基于MVC(Model-View-Controller)设计模式的Java ...

    Shiro框架政和

    - **Web集成**:Shiro可以与Spring MVC无缝配合,处理HTTP请求的安全过滤。 3. **Shiro核心组件**: - **Subject**:代表当前“安全主体”,即操作系统的用户。 - **Realm**:是Shiro与应用程序安全数据源(如...

    springMVC4.1.4+shiro1.2.3+spring4.x+Mybaits3.2.8+Ajax+html5

    在Spring MVC项目中,Shiro可以与Spring结合,提供安全控制,例如登录验证、权限控制等功能。通过Shiro,开发者可以方便地定义角色和权限,实现对用户访问资源的精细控制。 Spring 4.x 是Spring框架的一个版本,它...

    springmvc+shiro实现记住我功能以及权限缓存.rar

    此外,Shiro还可以配合Spring的缓存抽象,如Spring Cache,进一步优化缓存管理。 实现这些功能涉及的步骤可能包括以下几点: 1. 配置Shiro:在Spring MVC的配置文件中,我们需要定义Shiro的...

    spring-boot-shiro-demo

    配合Spring Boot的数据访问层,我们可以方便地从数据库中查询用户的角色和权限,并将这些信息映射到Shiro的权限模型中。 **3. Session共享** 在分布式系统中,Session共享是个挑战。Shiro提供了SessionManager和...

    spring boot 1.5.4 集成shiro+cas,实现单点登录和权限控制.docx

    在`pom.xml`中引入Apache Shiro的相关组件,包括`shiro-spring`、`shiro-ehcache`以及`shiro-cas`,这些依赖是Shiro与Spring整合以及实现CAS单点登录的基础。确保已经正确安装了CAS服务器,这里用的是版本3.5.2。 ...

    SpringAll_wuyouzhuguli.tar.gz

    循序渐进,学习Spring Boot、Spring Boot & Shiro、Spring Cloud、Spring Security & Spring Security OAuth2,博客Spring系列源码 一、Spring Boot教程 开启Spring Boot Spring Boot基础配置 Spring Boot中使用...

    mybatisplus-spring-boot_mybatis-plus整合_shiro_plus_源码.zip

    总的来说,MyBatisPlus、Spring Boot和Shiro Plus的整合是现代Web开发中常见的一种架构模式,它们相互配合,为开发者提供了高效、便捷、安全的开发环境。通过深入理解并掌握这三者的源码,开发者可以更好地优化代码...

    shiro登陆注销权限控制

    综上所述,这个项目是一个基于Spring Boot和Spring Cloud的分布式系统,使用Apache Shiro进行权限控制,通过Eureka实现服务注册与发现。数据库层面采用MySQL,用户信息和权限存储在数据库中,会话管理可能借助Redis...

    springboot整和jwt、shiro、redis实现token自动刷新

    Shiro是Java的一个安全框架,提供了会话管理、权限控制、身份认证等特性,与Spring Boot结合可以轻松实现权限控制。在Spring Boot中集成Shiro,我们可以通过编写自定义的Realm,对接JWT的验证逻辑,使得Shiro能够...

    整合shiro所需jar包

    在整合这些框架时,开发者通常会创建一个Shiro Realm来处理认证和授权,这个Realm可以与Spring的DataSource配合,从数据库中获取用户信息。同时,利用Spring的AOP特性,可以方便地在全局范围内处理Shiro的拦截器,...

    39.3 Spring Boot Shiro权限管理【从零开始学Spring Boot】

    在本主题中,我们将深入探讨如何使用Spring Boot与Apache Shiro进行权限管理。Spring Boot以其简洁的配置和快速的应用开发特性,已经成为了Java领域中的热门框架。而Shiro则是一款强大的安全框架,提供了身份验证、...

    shiro权限管理系统示例

    标签中提到的SSO,可能表示示例展示了如何使用Shiro与其他SSO服务配合使用。 4. **Spring Security比较**:虽然Shiro和Spring Security都是Java安全框架,但它们各有特点。Shiro更轻量级,易于理解和使用,适合小型...

Global site tag (gtag.js) - Google Analytics