1、What is Apache Shiro?
2、shiro demo: 身份认证使用textRealm
3、身份认证使用jdbcRealm
4、编程式授权
5、shiro + spring
1、What is Apache Shiro? <--返回目录
10 Minute Tutorial on Apache Shiro:http://shiro.apache.org/10-minute-tutorial.html
Apache Shiro is a powerful and easy to use Java security framework that offers developers an intuitive yet comprehensive solution to authentication, authorization, cryptography, and session management.
Shiro:java安全框架,提供认证、授权、加密和回话管理。
获取当前用户:
Subject currentUser = SecurityUtils.getSubject();
获取用户session:
Session session = currentUser.getSession();
session.setAttribute( "someKey", "aValue" );
用户认证:
if ( !currentUser.isAuthenticated() ) { //collect user principals and credentials in a gui specific manner //such as username/password html form, X509 certificate, OpenID, etc. //We'll use the username/password example here since it is the most common. UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa"); //this is all you have to do to support 'remember me' (no config - built in!): token.setRememberMe(true); currentUser.login(token); }
登陆失败的处理:
try { currentUser.login( token ); //if no exception, that's it, we're done! } catch ( UnknownAccountException uae ) { //username wasn't in the system, show them an error message? } catch ( IncorrectCredentialsException ice ) { //password didn't match, try again? } catch ( LockedAccountException lae ) { //account for that username is locked - can't login. Show them a message? } ... more types exceptions to check if you want ... } catch ( AuthenticationException ae ) { //unexpected condition - error? }
获取登陆用户的信息,比如用户名:
currentUser.getPrincipal()
判断登陆用户是否有指定角色或权限:
if ( currentUser.hasRole( "schwartz" ) ) { log.info("May the Schwartz be with you!" ); } else { log.info( "Hello, mere mortal." ); } if ( currentUser.isPermitted( "lightsaber:weild" ) ) { log.info("You may use a lightsaber ring. Use it wisely."); } else { log.info("Sorry, lightsaber rings are for schwartz masters only."); }
用户退出:
currentUser.logout();
2、shiro demo: 身份认证使用textRealm <--返回目录
依赖:
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.4</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.12</version> </dependency>
在classpath新建配置文件shiro.ini
[users]
java=123456
测试类
package com.oy; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; public class HelleWorld { public static void main(String[] args) { // 读取配置文件,初始化SecurityManager工厂 Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro.ini"); // 获取securityManager实例 SecurityManager securityManager=factory.getInstance(); // 把securityManager实例绑定到SecurityUtils SecurityUtils.setSecurityManager(securityManager); // 得到当前执行的用户 Subject currentUser=SecurityUtils.getSubject(); // 创建token令牌,用户名/密码 UsernamePasswordToken token=new UsernamePasswordToken("java", "123456"); try{ // 身份认证 currentUser.login(token); System.out.println("身份认证成功!"); }catch(AuthenticationException e){ e.printStackTrace(); System.out.println("身份认证失败!"); } // 退出 currentUser.logout(); } }
3、身份认证使用jdbcRealm <--返回目录
依赖:
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.4</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.37</version> </dependency>
数据库:
CREATE DATABASE IF NOT EXISTS `db_shiro` DEFAULT CHARACTER SET utf8; USE `db_shiro`; DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `userName` varchar(20) DEFAULT NULL, `password` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; insert into `users`(`id`,`userName`,`password`) values (1,'java','123456');
在classpath新建配置文件jdbc_shiro.ini
[main] jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm dataSource=com.mchange.v2.c3p0.ComboPooledDataSource dataSource.driverClass=com.mysql.jdbc.Driver dataSource.jdbcUrl=jdbc:mysql://localhost:3306/db_shiro dataSource.user=root dataSource.password=123456 jdbcRealm.dataSource=$dataSource securityManager.realms=$jdbcRealm
测试代码:
public static void main(String[] args) { // 读取配置文件,初始化SecurityManager工厂 Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:jdbc_shiro.ini"); // 获取securityManager实例 SecurityManager securityManager = factory.getInstance(); // 把securityManager实例绑定到SecurityUtils SecurityUtils.setSecurityManager(securityManager); // 得到当前执行的用户 Subject currentUser = SecurityUtils.getSubject(); // 创建token令牌,用户名/密码 UsernamePasswordToken token = new UsernamePasswordToken("java", "123456"); try { // 身份认证 currentUser.login(token); System.out.println("身份认证成功!"); } catch (AuthenticationException e) { e.printStackTrace(); System.out.println("身份认证失败!"); } // 退出 currentUser.logout(); }
4、编程式授权 <--返回目录
shiro_role.ini
[users] java=123456,role1,role2 jack=123456,role1
角色
@Test public void testHasRole() { Subject currentUser = ShiroUtils.login("classpath:shiro_role.ini", "java", "123456"); System.out.println(currentUser.hasRole("role1") ? "有role1这个角色" : "没有role1这个角色"); boolean[] results = currentUser.hasRoles(Arrays.asList("role1", "role2", "role3")); System.out.println(results[0] ? "有role1这个角色" : "没有role1这个角色"); System.out.println(results[1] ? "有role2这个角色" : "没有role2这个角色"); System.out.println(results[2] ? "有role3这个角色" : "没有role3这个角色"); System.out.println(currentUser.hasAllRoles(Arrays.asList("role1", "role2")) ? "role1,role2这两个角色都有" : "role1,role2这个两个角色不全有"); currentUser.logout(); } @Test public void testCheckRole() { Subject currentUser = ShiroUtils.login("classpath:shiro_role.ini", "java", "123456"); // checkRole,没有该角色报UnauthorizedException currentUser.checkRole("role1"); currentUser.checkRoles(Arrays.asList("role1", "role2")); currentUser.checkRoles("role1", "role2", "role3"); currentUser.logout(); }
shiro_permission.ini
[users] java=123456,role1,role2 jack=123,role1 [roles] role1=user:select role2=user:add,user:update,user:delete
权限
@Test public void testIsPermitted() { Subject currentUser = ShiroUtils.login("classpath:shiro_permission.ini", "java", "123456"); System.out.println(currentUser.isPermitted("user:select") ? "有user:select这个权限" : "没有user:select这个权限"); System.out.println(currentUser.isPermitted("user:update") ? "有user:update这个权限" : "没有user:update这个权限"); boolean results[] = currentUser.isPermitted("user:select", "user:update", "user:delete"); System.out.println(results[0] ? "有user:select这个权限" : "没有user:select这个权限"); System.out.println(results[1] ? "有user:update这个权限" : "没有user:update这个权限"); System.out.println(results[2] ? "有user:delete这个权限" : "没有user:delete这个权限"); System.out.println(currentUser.isPermittedAll("user:select", "user:update") ? "有user:select,update这两个权限" : "user:select,update这两个权限不全有"); currentUser.logout(); } @Test public void testCheckPermitted() { Subject currentUser = ShiroUtils.login("classpath:shiro_permission.ini", "java", "123456"); currentUser.checkPermission("user:select"); currentUser.checkPermissions("user:select", "user:update", "user:delete"); currentUser.logout(); }
ShiroUtils
package com.oy.common; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; public class ShiroUtils { public static Subject login(String configFile, String userName, String password) { // 读取配置文件,初始化SecurityManager工厂 Factory<SecurityManager> factory = new IniSecurityManagerFactory(configFile); // 获取securityManager实例 SecurityManager securityManager = factory.getInstance(); // 把securityManager实例绑定到SecurityUtils SecurityUtils.setSecurityManager(securityManager); // 得到当前执行的用户 Subject currentUser = SecurityUtils.getSubject(); // 创建token令牌,用户名/密码 UsernamePasswordToken token = new UsernamePasswordToken(userName, password); try { // 身份认证 currentUser.login(token); System.out.println("身份认证成功!"); } catch (AuthenticationException e) { e.printStackTrace(); System.out.println("身份认证失败!"); } return currentUser; } }
5、shiro + spring <--返回目录
依赖:
<!-- 添加Servlet支持 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.1</version> </dependency> <!-- 添加jstl支持 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- 添加Spring支持 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.1.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.1.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>4.1.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.1.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.1.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.1.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.1.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.1.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>4.1.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.1.7.RELEASE</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.2.3</version> </dependency> <!-- 添加日志支持 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- 添加mybatis支持 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.3.0</version> </dependency> <!-- jdbc驱动包 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.37</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.4</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.2.4</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.4</version> </dependency>
web.xml
<!-- shiro过滤器定义 --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 --> <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> <!-- Spring配置文件 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- 编码过滤器 --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <async-supported>true</async-supported> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Spring监听器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 添加对springmvc的支持 --> <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet> <servlet-mapping> <servlet-name>springMVC</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
application.xml中shiro相关配置
<!-- 自定义Realm --> <bean id="myRealm" class="com.java1234.realm.MyRealm"/> <!-- 安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="myRealm"/> </bean> <!-- Shiro过滤器 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- Shiro的核心安全接口,这个属性是必须的 --> <property name="securityManager" ref="securityManager"/> <!-- 身份认证失败,则跳转到登录页面的配置 --> <property name="loginUrl" value="/index.jsp"/> <!-- 权限认证失败,则跳转到指定页面 --> <property name="unauthorizedUrl" value="/unauthor.jsp"/> <!-- Shiro连接约束配置,即过滤链的定义 --> <property name="filterChainDefinitions"> <value> /login=anon /admin*=authc /student=roles[teacher] /teacher=perms["user:create"] </value> </property> </bean> <!-- 保证实现了Shiro内部lifecycle函数的bean执行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <!-- 开启Shiro注解 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean>
自定义Realm
public class MyRealm extends AuthorizingRealm{ @Resource private UserService userService; /** * 验证当前登录的用户 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String userName=(String)token.getPrincipal(); User user=userService.getByUserName(userName); if(user!=null){ AuthenticationInfo authcInfo=new SimpleAuthenticationInfo(user.getUserName(),user.getPassword(),"xx"); return authcInfo; }else{ return null; } } /** * 为当限前登录的用户授予角色和权 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String userName=(String)principals.getPrimaryPrincipal(); SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo(); authorizationInfo.setRoles(userService.getRoles(userName)); authorizationInfo.setStringPermissions(userService.getPermissions(userName)); return authorizationInfo; } }
登陆
/** * 用户Controller * @author oy */ @Controller @RequestMapping("/user") public class UserController { /** * 用户登录 * @param user * @param request * @return */ @RequestMapping("/login") public String login(User user,HttpServletRequest request){ Subject subject=SecurityUtils.getSubject(); UsernamePasswordToken token=new UsernamePasswordToken(user.getUserName(), user.getPassword()); try{ subject.login(token); Session session=subject.getSession(); System.out.println("sessionId:"+session.getId()); System.out.println("sessionHost:"+session.getHost()); System.out.println("sessionTimeout:"+session.getTimeout()); session.setAttribute("info", "session的数据"); return "redirect:/success.jsp"; }catch(Exception e){ e.printStackTrace(); request.setAttribute("user", user); request.setAttribute("errorMsg", "用户名或密码错误!"); return "index"; } } }