Apache Shiro 是一个框架,可用于身份验证和授权。本文提供了几个示例用来展示如何在 Java™ 应用程序中使用 Shiro 并给出了如何在一个 Grails web 应用程序中使用它的概述。为了从本文中最大限度地受益,您应该习惯于创建 Java 应用程序并安装了如下的几个组件:
- Java 1.6 JDK
- Grails(用来运行这些 web 应用程序示例)
在对系统进行安全保障时,有两个安全性元素非常重要:身份验证和授权。虽然这两个术语代表的是不同的含义,但出于它们在应用程序安全性方面各自的角色考虑,它们有时会被交换使用。身份验证和授权
身份验证 指的是验证用户的身份。在验证用户身份时,需要确认用户的身份的确如他们所声称的那样。在大多数应用程序中,身份验证是通过用户名和密码的组合完成的。只要用户选择了他人很难猜到的密码,那么用户名和密码的组合通常就足以确立身份。但是,还有其他的身份验证方式可用,比如指纹、证书和生成键。
一旦身份验证过程成功地建立起身份,授权 就会接管以便进行访问的限制或允许。 所以,有这样的可能性:用户虽然通过了身份验证可以登录到一个系统,但是未经过授权,不准做任何事情。还有一种可能是用户虽然具有了某种程度的授权,却并未经过身份验证。
在为应用程序规划安全性模型时,必须处理好这两个元素以确保系统具有足够的安全性。身份验证是应用程序常见的问题(特别是在只有用户和密码组合的情况下),所以让框架来处理这项工作是一个很好的做法。合理的框架可提供经过测试和维护的优势,让您可以集中精力处理业务问题,而不是解决其解决方案已经实现的问题。
Apache Shiro 提供了一个可用的安全性框架,各种客户机都可将这个框架应用于它们的应用程序。本文中的这些例子旨在介绍 Shiro 并着重展示对用户进行身份验证的基本任务。
了解 Shiro
Shiro 是一个用 Java 语言实现的框架,通过一个简单易用的 API 提供身份验证和授权。使用 Shiro,您就能够为您的应用程序提供安全性而又无需从头编写所有代码。
Shiro 的 Session
对象允许无需 HttpSession
即可使用一个用户会话。通过使用一个通用的 Session
对象,即便该代码没有在一个 Web 应用程序中运行,仍可以使用相同的代码。没有对应用服务器或 Web 应用服务器会话管理的依赖,您甚至可以在命令行环境中使用 Shiro。换言之,使用 Shiro 的 API 编写的代码让您可以构建连接到 LDAP 服务器的命令行应用程序并且与 web 应用程序内用来访问 LDAP 服务器的代码相同。由于 Shiro 提供具有诸多不同数据源的身份验证,以及 Enterprise Session Management,所以是实现单点登录(SSO)的理想之选 — 大型企业内的一个理想特性,因为在大型企业内,用户需要在一天内经常登录到并使用不同系统。这些数据源包括 JDBC、LDAP、 Kerberos 和 Microsoft® Active Directory® Directory Services (AD DS)。
shiro-springmvc-mybatis登录认证 权限控制
1:shiro jar
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-core</artifactId>
- <version>1.2.3</version>
- </dependency>
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-spring</artifactId>
- <version>1.2.3</version>
- </dependency>
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-cas</artifactId>
- <version>1.2.3</version>
- <exclusions>
- <exclusion>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-web</artifactId>
- <version>1.2.3</version>
- </dependency>
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-ehcache</artifactId>
- <version>1.2.3</version>
- </dependency>
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-quartz</artifactId>
- <version>1.2.3</version>
- </dependency>
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd">
- <description>Shiro Configuration</description>
- <!-- 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" />
- <property name="cacheManager" ref="cacheManager" />
- </bean>
- <!-- 項目自定义的Realm认证登录 授权 -->
- <bean id="shiroDbRealm" class="com.cat.shiro.ShiroRealm">
- <property name="cacheManager" ref="cacheManager" />
- </bean>
- <!-- Shiro Filter -->
- <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
- <property name="securityManager" ref="securityManager" />
- <property name="successUrl" value="/govern/pages/member/index" />
- <property name="loginUrl" value="/govern/pages/login" />
- <property name="unauthorizedUrl" value="/govern/pages/err" />
- <!-- <property name="filters">
- <map>
- <entry key="authc" value-ref="shiro"></entry>
- </map>
- </property> -->
- <property name="filterChainDefinitions">
- <value>
- <!-- 静态资源允许访问 -->
- <!-- anon 允许访问 -->
- /login/logincs.do = anon
- /login/submitcs.do = anon
- <!-- authc需要授权 -->
- /** = authc
- </value>
- </property>
- </bean>
- <!-- <bean id="shiro" class="com.cat.shiro.ShiroFilter">
- </bean> -->
- <!-- 用户授权信息Cache -->
- <bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />
- <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
- <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
- <!-- AOP式方法级权限检查 -->
- <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
- depends-on="lifecycleBeanPostProcessor">
- <property name="proxyTargetClass" value="true" />
- </bean>
- <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
- <property name="securityManager" ref="securityManager" />
- </bean>
- </beans>
3:web.xml 对应配置
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- classpath:conf/shiro.xml
- </param-value>
- </context-param>
- <filter>
- <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>
4:springmvc.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/mvc
- http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx-3.0.xsd ">
- <!-- 加载包中的controller 注解扫描包 -->
- <context:component-scan base-package="com.hnust.controller">
- <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
- </context:component-scan>
- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
- <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
- <!--配置拦截器, 多个拦截器,顺序执行 -->
- <!-- 匹配的是url路径 -->
- <!-- <mvc:mapping path="/user/**" /> <mvc:mapping path="/test/**" /> -->
- <!-- 当设置多个拦截器时,先按顺序调用preHandle方法,然后逆序调用每个拦截器的postHandle和afterCompletion方法 -->
- <!-- 测试shiro权限控制 暂时去掉自带的权限控制 <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/*/*" /> <bean
- class="com.hnust.interceptor.LoginInterceptor"></bean> </mvc:interceptor> </mvc:interceptors> -->
- <!-- 静态资源的访问 -->
- <!-- 视图分解器 -->
- <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
- <property name="prefix" value="/govern/" />
- <property name="suffix" value=".jsp" />
- </bean>
- <!-- 国际化的消息资源文件(本系统中主要用于显示/错误消息定制) -->
- <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
- <property name="basenames">
- <list>
- <!-- 在web环境中一定要定位到classpath 否则默认到当前web应用下找 -->
- <value>classpath:/messages</value>
- </list>
- </property>
- <property name="useCodeAsDefaultMessage" value="false" />
- <property name="defaultEncoding" value="UTF-8" />
- <property name="cacheSeconds" value="60" />
- </bean>
- <!-- 避免IE在ajax请求时,返回json出现下载 -->
- <bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
- <property name="supportedMediaTypes">
- <list>
- <value>text/html;charset=UTF-8</value>
- </list>
- </property>
- </bean>
- <!-- 上传文件的解析器 -->
- <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
- <property name="defaultEncoding" value="utf-8" />
- <property name="maxUploadSize" value="10485760000" />
- <property name="maxInMemorySize" value="40960" />
- </bean>
- <!-- 支持Shiro对Controller的方法级AOP安全控制 begin -->
- <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
- depends-on="lifecycleBeanPostProcessor">
- <property name="proxyTargetClass" value="true" />
- </bean>
- <!-- 无权限 控制后台不报错 -->
- <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
- <property name="exceptionMappings">
- <props>
- <prop key="org.apache.shiro.authz.UnauthorizedException">405</prop>
- <prop key="java.lang.Throwable">405</prop>
- </props>
- </property>
- </bean>
- </beans>
5:spring.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/mvc
- http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx-3.0.xsd ">
- <!-- 引入jdbc配置文件 -->
- <context:property-placeholder location="classpath:conf/jdbc.properties" />
- <context:annotation-config />
- <!-- 使用Annotation自动注册Bean,解决事物失效问题:在主容器中不扫描@Controller注解,在SpringMvc中只扫描@Controller注解。 -->
- <!-- 扫描service、dao组件 --> <!-- base-package 如果多个,用“,”分隔 -->
- <context:component-scan base-package="com.hnust">
- <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
- </context:component-scan>
- <!-- 分解配置 jdbc.properites -->
- <!-- 数据源c3p0 -->
- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
- <property name="driverClassName" value="${driverClassName}" />
- <property name="url" value="${url}" />
- <property name="username" value="${username}" />
- <property name="password" value="${password}" />
- <!-- <property name="maxPoolSize" value="${c3p0.pool.size.max}" /> <property name="minPoolSize" value="${c3p0.pool.size.min}"
- /> <property name="initialPoolSize" value="${c3p0.pool.size.ini}" /> <property name="acquireIncrement"
- value="${c3p0.pool.size.increment}" /> -->
- </bean>
- <!-- sessionFactory 将spring和mybatis整合 -->
- <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
- <property name="dataSource" ref="dataSource" />
- <property name="configLocation" value="classpath:conf/mybatis-config.xml" />
- <property name="mapperLocations" value="classpath:mapper/*.xml" /> <!-- 加载mapper文件 -->
- </bean>
- <!-- 注入工具类 -->
- <bean id="baseDao" class="com.hnust.base.BaseDao">
- <property name="sqlSessionFactory">
- <ref bean="sqlSessionFactory" />
- </property>
- </bean>
- <!-- 事务 -->
- <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- </bean>
- <tx:advice id="txAdvice" transaction-manager="txManager">
- <tx:attributes>
- <tx:method name="insert*" propagation="REQUIRED" />
- <tx:method name="update*" propagation="REQUIRED" />
- <tx:method name="delete*" propagation="REQUIRED" />
- <tx:method name="find" read-only="true" />
- <tx:method name="get" read-only="true" />
- <tx:method name="*" propagation="REQUIRED" />
- </tx:attributes>
- </tx:advice>
- <aop:config>
- <aop:pointcut expression="execution(* com.hnust.service.impl.*.*(..))" id="pointCut" />
- <aop:advisor advice-ref="txAdvice" pointcut-ref="pointCut" />
- </aop:config>
- </beans>
当前贴出来的类对应 上面2 配置文件
pojo类就不贴了 我这里没连数据 只是模拟的用户登录 和手动添加的权限
- /**
- *
- */
- package com.cat.shiro;
- import java.util.ArrayList;
- import java.util.List;
- import org.apache.shiro.authc.AuthenticationException;
- import org.apache.shiro.authc.AuthenticationInfo;
- import org.apache.shiro.authc.AuthenticationToken;
- import org.apache.shiro.authc.SimpleAuthenticationInfo;
- import org.apache.shiro.authc.UsernamePasswordToken;
- import org.apache.shiro.authz.AuthorizationException;
- import org.apache.shiro.authz.AuthorizationInfo;
- import org.apache.shiro.authz.SimpleAuthorizationInfo;
- import org.apache.shiro.realm.AuthorizingRealm;
- import org.apache.shiro.subject.PrincipalCollection;
- import com.cat.spring.entity.Role;
- import com.cat.spring.entity.User;
- /**
- */
- public class ShiroRealm extends AuthorizingRealm {
- /*
- * 授权
- */
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(
- PrincipalCollection principals) {
- // 根据用户配置用户与权限
- if (principals == null) {
- throw new AuthorizationException(
- "PrincipalCollection method argument cannot be null.");
- }
- String name = (String) getAvailablePrincipal(principals);
- List<String> roles = new ArrayList<String>();
- // 简单默认一个用户与角色,实际项目应User user = userService.getByAccount(name);
- // 根据用户名查询出用户 判断用户信息的有效性 然获取用户的角色权限 授权
- User user = new User("shiro", "123456");
- if (user.getName().equals(name)) {
- // 模拟三个角色
- for (int x = 0; x < 3; x++) {
- roles.add("user" + x);
- }
- } else {
- throw new AuthorizationException();
- }
- SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
- // 增加角色
- // 取出所有角色授权
- info.addRoles(roles);
- // 取出所有权限授权
- // info.addStringPermissions(permissions);
- // 模拟拥有的权限
- info.addStringPermission("cp:updatecs,updatecs1");
- return info;
- }
- /*
- * 认证登录
- */
- @SuppressWarnings("unused")
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(
- AuthenticationToken authcToken) throws AuthenticationException {
- UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
- // 简单默认一个用户,实际项目应User user =
- // userService.getByAccount(token.getUsername());
- User user = new User("shiro", "123456");
- if (user == null) {
- throw new AuthorizationException();
- }
- SimpleAuthenticationInfo info = null;
- if (user.getName().equals(token.getUsername())) {
- info = new SimpleAuthenticationInfo(user.getName(),
- user.getPassword(), getName());
- }
- return info;
- }
- }
7:logincontroller
- package com.hnust.controller;
- @Controller
- @RequestMapping(value = "/login")
- public class LoginController {
- /*****************测试shiro************************************/
- @RequestMapping(value = "/logincs", method = RequestMethod.GET)
- public String logincs() {
- return "/pages/login";
- }
- @RequestMapping(value = "/submitcs", method = RequestMethod.POST)
- public String submitcs(String username, String password) {
- User user = new User("shiro", "123456");
- try {
- // 如果登陆成功
- if (user.getName().equals(username)
- && user.getPassword().equals(password)) {
- UsernamePasswordToken token = new UsernamePasswordToken(
- user.getName(), user.getPassword().toString());
- Subject subject = SecurityUtils.getSubject();
- subject.login(token);
- return "/pages/member/index";
- } else {
- return "/pages/login";
- }
- } catch (Exception e) {
- e.printStackTrace();
- return "/pages/login";
- }
- }
- }
8:测试权限类 对应上面6 类里面设置的权限访问URL
- package com.hnust.controller;
- @Controller
- @RequestMapping(value = "/cp")
- public class CompanyController extends BaseController{
- /**
- * updatecs
- */
- @RequiresPermissions("cp:updatecs")
- @RequestMapping(value="/updatecs",method=RequestMethod.GET)
- public String updatecs(){
- System.err.println("成功1");
- return "index";
- }
- /**
- * updatecs
- */
- @RequiresPermissions("cp:updatecs1")
- @RequestMapping(value="/updatecs1",method=RequestMethod.GET)
- public String updatecs1(){
- System.err.println("成功2");
- return "index";
- }
- /**
- * updatecs 这个我没用给当前用户添加权限 是会提示无权限的
- */
- @RequiresPermissions("cp:updatecs2")
- @RequestMapping(value="/updatecs2",method=RequestMethod.GET)
- public String updatecs2(){
- // System.err.println("失败");
- return "index";
- }
- }
9:下面贴出 效果图
登录不做权限验证:
登录成功:
下面开始进行权限认证:
这是我当前角色有的权限 所以去到了我指定的页面
下面进行 没有权限的URL访问: