标签:pre any 字符串 拦截器 mes error 斜杠 cli isp
shiro是一个安全框架,主要可以帮助我们解决程序开发中认证和授权的问题。基于拦截器做的权限系统,权限控制的粒度有限,为了方便各种各样的常用的权限管理需求的实现,,我们有必要使用比较好的安全框架,早期spring security 作为一个比较完善的安全框架比较火,但是spring security学习成本比较高,于是就出现了shiro安全框架,学习成本降低了很多,而且基本的功能也比较完善。
1、Authentication:身份认证/登陆,验证用户是不是拥有相对应的身份;
2、Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者粒度的验证某个用户对某个资源是否具有权限;
3、Session Manager:会话管理,即用户登陆后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是Web环境的;
4、Cryptographt:加密,保护数据,如密码加密存储到数据库,而不是明文存储;
5、Web Support:Web支持,可以非常容易的继承到Web环境的;
6、Caching:缓存,比如用户登陆后,其用户信息、拥有的角色/权限不必每次去查,这样提高效率;
7、Concurrency:shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
8、Testing:提供测试支持;
9、Run As:允许一个用户假装另一个用户(如果我们允许)的身份进行访问;
10、Remember Me:记住我,这个是非常常见的功能,即一次登陆后,下次再来的话不用登陆了。
Subject:主题 被验证的对象,一般指的当前用户对象。但是不仅仅可以指当前用户对象,还可以是其他东西,线程等等。spring mvc中一个一个的用户的请求。
SecurityManager:安全认证管理器。是shiro的核心,会在安全认证管理器中所做所有的认证操作。类似于之前spring mvc中的前端控制器(DispacherServlet)。
Realm:域的意思。负责访问安全认证数据。shiro框架并不存在安全认证数据,安全认证数据需要用户自己存储。shiro支持很多的Realm实现,也就是说安全认证数据我们可以放到数据库中,也可以放到文件中等等。可以把realm理解为以前web项目的dao层。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <modelVersion>4.0.0</modelVersion> 6 <groupId>aaa</groupId> 7 <artifactId>test_shiro_qy97_02</artifactId> 8 <version>1.0-SNAPSHOT</version> 9 <dependencies> 10 <dependency> 11 <groupId>commons-logging</groupId> 12 <artifactId>commons-logging</artifactId><version>1.0.4</version> 13 </dependency> 14 <dependency> 15 <groupId>org.apache.shiro</groupId> 16 <artifactId>shiro-core</artifactId> 17 <version>1.3.0</version> 18 </dependency> 19 <!-- 导入shiro和spring继承的jar包 --> 20 <dependency> 21 <groupId>org.apache.shiro</groupId> 22 <artifactId>shiro-spring</artifactId> 23 <version>1.2.3</version> 24 </dependency> 25 <!-- 导入shiro和web的jar包--> 26 <dependency> 27 <groupId>org.apache.shiro</groupId> 28 <artifactId>shiro-web</artifactId> 29 <version>1.2.3</version> 30 </dependency> 31 </dependencies> 32 </project>
1 <filter> 2 <filter-name>shiroFilter</filter-name> 3 <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 4 <init-param> 5 <!--保证该过滤器的生命周期和spring 工厂中shiro过滤器对象的生命周期一致--> 6 <param-name>targetFilterLifecycle</param-name> 7 <param-value>true</param-value> 8 </init-param> 9 <!--声明该过滤器代理工厂类中的id为什么的shiro过滤器对象--><init-param> 10 <param-name>targetBeanName</param-name> 11 <param-value>shiroFilter</param-value> 12 </init-param> 13 </filter> 14 <filter-mapping> 15 <filter-name>shiroFilter</filter-name> 16 <url-pattern>/*</url-pattern> 17 </filter-mapping>
shiro的配置信息比较多,一般不和spring的主配置文件放到一起,一般都会单独建立一个shiro和spring继承的配置文件,创建好之后,在spring.xml中引入该文件。
spring-shiro中配置:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd"> 6 <!--创建自定义域对象--> 7 <bean id="authRealm" class="com.aaa.ssm.realm.AuthRealm"></bean> 8 <!--创建shiro的安全管理器对象--> 9 <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> 10 <!--要声明域,在域中读取认证和授权的数据--> 11 <property name="realm" ref="authRealm"></property> 12 </bean> 13 <!--创建shiro的过滤器对象--> 14 <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> 15 <!--要注入安全管理器对象--> 16 <property name="securityManager" ref="securityManager"></property> 17 <!--配置登录请求的路径--> 18 <property name="loginUrl" value="/user/login.do"></property> 19 <!--配置shiro认证和授权的过滤器--> 20 <property name="filterChainDefinitions"> 21 <value> 22 <!--对静态资源不拦截--> 23 <!--anon指匿名访问的过滤器,所有匿名用户都可以访问static下面的资源--> 24 /static/*=anon 25 /user/login.do=anon 26 /login.jsp=anon 27 <!--authc指必须经过认证(登录过之后)才能访问的请求 /*代表所有有一个斜杠的请求都要经过认证 --> 28 /*=authc 29 /*/*=authc 30 </value> 31 </property></bean> 32 </beans>
1 package com.aaa.ssm.realm; 2 import com.aaa.ssm.entity.Users; 3 import com.aaa.ssm.service.UserService; 4 import org.apache.shiro.authc.*import org.apache.shiro.authz.AuthorizationInfo; 5 import org.apache.shiro.realm.AuthorizingRealm; 6 import org.apache.shiro.realm.Realm; 7 import org.apache.shiro.subject.PrincipalCollection; 8 import org.springframework.beans.factory.annotation.Autowired; 9 /** 10 * 实现自定义域 11 * Authorization 授权(权限校验) 12 * 13 * Authentication 认证(登录校验) 14 * 15 */ 16 public class AuthRealm extends AuthorizingRealm { 17 @Autowired 18 private UserService userService; 19 //获取授权信息 20 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { 21 return null; 22 }//获取认证信息 23 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws 24 AuthenticationException { 25 //获取用户名 不过一般往shiro中放置用户身份信息的时候,不直接放用户名字符串,放用户对象 26 String username = token.getPrincipal().toString(); 27 //有了用户名,要根据用户名在数据库中查询用户对象 28 Users user = userService.findByUsername(username); 29 //判断如果用户对象不存在,抛出UnknownAccountException 30 if(user==null){ 31 throw new UnknownAccountException("用户名不存在"); 32 } 33 //封装用户的身份对象 返回这个身份对象 34 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),"authRealm"); 35 return info; 36 } 37 }
1 /** 2 * 用户登录的请求 3 * @param user 4 * @return 5 */ 6 @RequestMapping("/login") 7 public String login(Users user, Model model, HttpSession session){ 8 /* user = userService.checkUser(user)//判断user是否为空 9 if(user!=null){ 10 //用户名和密码输入正确 11 //登录成功之后把用户对象放置到session中 12 //登录成功之后,查询用户能操作的模块 13 session.setAttribute(Constants.SESSION_USER,user); 14 List<Module> oneModules = userService.queryUsersModules(user); 15 //获取用户能操作的所有模块的路径,放置到session中 16 List<String> permiteUrls = userService.queryPermitUrls(oneModules); 17 session.setAttribute(Constants.PERMIT_URLS,permiteUrls); 18 model.addAttribute("oneModules",oneModules); 19 return "index"; 20 }else{ 21 return "redirect:/login.jsp"; 22 }*/ 23 //获取用户的主体对象就可以了 24 Subject subject = SecurityUtils.getSubject();//封装用户名和密码的认证信息对象 25 UsernamePasswordToken upt = new UsernamePasswordToken(user.getUsername(),user.getPassword()); 26 //进行登录认证 27 try { 28 subject.login(upt); 29 }catch (Exception e){ 30 e.printStackTrace(); 31 System.out.println("用户名或者密码错误"); 32 return "redirect:/login.jsp"; 33 } 34 return "index"; 35 }
一般在数据库中存储明文的密码是不安全的,一般都会对项目中的密码进行加密。加密算法分为两大类,一类是可逆加密,另一类是不可逆加密。可逆加密分两类,一类是堆成加密,另外一类是非对称加密。一般对称加密的私钥在客户端和服务器端都是一致的。非对称加密私钥在客户端和服务器端是不一样的。非可逆加密,任何加密算法的安全性都要建立在你的源码已经被别人获取的情况下还算安全,那这种加密算法才算是成功的,这就是非可逆加密。常用的非可逆加密算法有MD5和SHA1,SHA256等等。
1 package com.aaa.ssm.util; 2 import org.apache.shiro.crypto.hash.SimpleHash; 3 /** 4 * 测试非可逆加密算法 5 */ 6 public class PasswordUtil { 7 public static void main(String[] args) { 8 String str = "123456"; 9 //第一个参数代表加密使用的算法 第二个参数要加密的字符串 第三个参数 加入的盐的值 第四个参数 hash迭代的次数 10 //以后再保存用户的密码应该使用加密算法加密 11 SimpleHash simpleHash = new SimpleHash("md5",str,"123",10); 12 String code = simpleHash.toString(); 13 System.out.println("加密后的密文:"+code); 14 } 15 }
密码加密存储之后,在使用shiro做校验,应该在realm中做如下配置:
1 <!--创建自定义域对象--> 2 <bean id="authRealm" class="com.aaa.ssm.realm.AuthRealm"> 3 <property name="credentialsMatcher" ref="credentialsMatcher"></property> 4 </bean> 5 <!-- 创建凭证匹配器对象--> 6 <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> 7 <!--指定要对用户传过来的明文的密码最什么加密--> 8 <property name="hashAlgorithmName" value="md5"></property> 9 <!--指明hash迭代的次数--> 10 <property name="hashIterations" value="10"></property> 11 </bean>
在自定义的realm中,传入用户密码对应的盐值:
1 package com.aaa.ssm.realm; 2 3 import com.aaa.ssm.entity.Module; 4 import com.aaa.ssm.entity.Users; 5 import com.aaa.ssm.service.IUserServiceDAO; 6 import org.apache.shiro.authc.*; 7 import org.apache.shiro.authz.AuthorizationInfo; 8 import org.apache.shiro.authz.SimpleAuthorizationInfo; 9 import org.apache.shiro.realm.AuthorizingRealm; 10 import org.apache.shiro.subject.PrincipalCollection; 11 import org.apache.shiro.util.ByteSource; 12 import org.springframework.beans.factory.annotation.Autowired; 13 14 import java.util.List; 15 16 /** 17 * 实现自定义域 18 * Authorization 授权(权限校验) 19 * 20 * Authentication 认证(登录校验) 21 * 22 */ 23 public class AuthRealm extends AuthorizingRealm { 24 25 @Autowired 26 private IUserServiceDAO userService; 27 //获取授权信息 28 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { 29 //获取当前的用户对象 30 Users user = (Users) principalCollection.getPrimaryPrincipal(); 31 //查询用户有哪些权限 32 List<Module> modules = userService.userModule(user); 33 List<String> namespaces = userService.queryPrimaryUrl(modules); 34 //创建授权对象 35 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); 36 //把用户能操作的资源的信息放置到授权对象中 37 info.addStringPermissions(namespaces); 38 return info; 39 } 40 41 //获取认证信息 42 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 43 Object pri = token.getPrincipal(); 44 if(pri==null){ 45 throw new UnknownAccountException("用户名为空"); 46 } 47 //获取用户名 不过一般往shiro中放置用户身份信息的时候,不直接放用户名字符串,放用户对象 48 String username = pri.toString(); 49 //有了用户名,要根据用户名在数据库中查询用户对象 50 Users user = userService.findByUsername(username); 51 //判断如果用户对象不存在,抛出UnknownAccountException 52 if(user==null){ 53 throw new UnknownAccountException("用户名不存在"); 54 } 55 //盐值一般每个用户是不一样的 56 ByteSource bytes = ByteSource.Util.bytes("123"); 57 //封装用户的身份对象 返回这个身份对象 58 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),bytes,"authRealm"); 59 return info; 60 } 61 }
1 <!--创建shiro的过滤器对象--> 2 <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> 3 <!--要注入安全管理器对象--> 4 <property name="securityManager" ref="securityManager"></property> 5 <!--配置登录请求的路径--> 6 <property name="loginUrl" value="/user/toLogin.do"></property> 7 <!--如果用户没有经过授权跳转到的错误界面--> 8 <property name="unauthorizedUrl" value="/error.jsp"></property> 9 <!--配置shiro认证和授权的过滤器--> 10 <property name="filterChainDefinitions"> 11 <value> 12 <!--对静态资源不拦截--> 13 <!--anon指匿名访问的过滤器,所有匿名用户都可以访问static下面的资源--> 14 /static/*=anon 15 /user/login.do=anon 16 <!--不拦截跳转到主界面的请求--> 17 /user/index.do=anon 18 <!--配置登出请求的过滤器--> 19 /user/logout.do=logout 20 <!--配置/user/list.do必须有user的权限才能访问--> 21 /user/list.do=anon 22 /role/*.do=perms[role] 23 <!--authc指必须经过认证(登录过之后)才能访问的请求 /*代表所有有一个斜杠的请求都要经过认证 --> 24 /*=authc 25 /*/*=authc 26 </value> 27 </property> 28 </bean>
AuthorizationInfo)
1 package com.aaa.ssm.realm; 2 3 import com.aaa.ssm.entity.Module; 4 import com.aaa.ssm.entity.Users; 5 import com.aaa.ssm.service.IUserServiceDAO; 6 import org.apache.shiro.authc.*; 7 import org.apache.shiro.authz.AuthorizationInfo; 8 import org.apache.shiro.authz.SimpleAuthorizationInfo; 9 import org.apache.shiro.realm.AuthorizingRealm; 10 import org.apache.shiro.subject.PrincipalCollection; 11 import org.apache.shiro.util.ByteSource; 12 import org.springframework.beans.factory.annotation.Autowired; 13 14 import java.util.List; 15 16 /** 17 * 实现自定义域 18 * Authorization 授权(权限校验) 19 * 20 * Authentication 认证(登录校验) 21 * 22 */ 23 public class AuthRealm extends AuthorizingRealm { 24 25 @Autowired 26 private IUserServiceDAO userService; 27 //获取授权信息 28 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { 29 //获取当前的用户对象 30 Users user = (Users) principalCollection.getPrimaryPrincipal(); 31 //查询用户有哪些权限 32 List<Module> modules = userService.userModule(user); 33 List<String> namespaces = userService.queryPrimaryUrl(modules); 34 //创建授权对象 35 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); 36 //把用户能操作的资源的信息放置到授权对象中 37 info.addStringPermissions(namespaces); 38 return info; 39 } 40 41 //获取认证信息 42 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 43 Object pri = token.getPrincipal(); 44 if(pri==null){ 45 throw new UnknownAccountException("用户名为空"); 46 } 47 //获取用户名 不过一般往shiro中放置用户身份信息的时候,不直接放用户名字符串,放用户对象 48 String username = pri.toString(); 49 //有了用户名,要根据用户名在数据库中查询用户对象 50 Users user = userService.findByUsername(username); 51 //判断如果用户对象不存在,抛出UnknownAccountException 52 if(user==null){ 53 throw new UnknownAccountException("用户名不存在"); 54 } 55 //盐值一般每个用户是不一样的 56 ByteSource bytes = ByteSource.Util.bytes("123"); 57 //封装用户的身份对象 返回这个身份对象 58 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),bytes,"authRealm"); 59 return info; 60 } 61 }
1 <dependency> 2 <groupId>org.springframework</groupId> 3 <artifactId>spring-aop</artifactId> 4 <version>${spring.version}</version</dependency> 5 <!-- aspectj相关jar包--> 6 <dependency> 7 <groupId>org.aspectj</groupId> 8 <artifactId>aspectjrt</artifactId> 9 <version>1.7.4</version></dependency> 10 <dependency> 11 <groupId>org.aspectj</groupId> 12 <artifactId>aspectjweaver</artifactId> 13 <version>1.7.4</version> 14 </dependency>
1 <!--开启aop--> 2 <aop:config proxy-target-class="true"></aop:config> 3 <!--开启shiro的aop注解的支持--> 4 <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor" > 5 <property name="securityManager" ref="securityManager"></property> 6 </bean>
1 <!--声明spring mvc的统一异常处理界面--> 2 <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> 3 <property name="defaultErrorView" value="../../error"></property> 4 </bean>
shiro中提供的类似于web中的session的机制
1 /** 2 * 跳转到系统管理的主界面 3 * @return 4 */ 5 @RequestMapping("/index") 6 public String index(Model model){ 7 //可以通过Subject获取shiro会话中的用户身份对象 8 Users user = (Users)SecurityUtils.getSubject().getPrincipal(); 9 List<Module> oneModules = userService.queryUsersModules(user); 10 model.addAttribute("oneModules",oneModules); 11 return "index"; 12 } 13 /** 14 * 用户登录的请求 15 * @param user 16 * @return 17 */ 18 @RequestMapping("/login") 19 public String login(Users user, Model model, HttpSession session){ 20 //获取用户的主体对象就可以了 21 Subject subject = SecurityUtils.getSubject(); 22 //封装用户名和密码的认证信息对象 23 UsernamePasswordToken upt = new UsernamePasswordToken(user.getUsername(),user.getPassword()); 24 //进行登录认证try { 25 subject.login(upt); 26 }catch (Exception e){ 27 e.printStackTrace(); 28 model.addAttribute("error","用户名或者密码错误"); 29 return "login"; 30 } 31 return "redirect:/user/index.do"; 32 }
tomcat的session可以控制超时时间,shiro的session也可以控制。如果需要控制类似于超时时间这些session的属性,就需要在shiro的主配置文件中配置sessionManager对象
1 <!--创建会话管理器对象--> 2 <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> 3 <!--配置session的超时时间,默认单位是毫秒--> 4 <property name="globalSessionTimeout" value="1000"></property> 5 </bean> 6 <!--创建shiro的安全管理器对象--> 7 <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> 8 <!--要声明域,在域中读取认证和授权的数据--> 9 <property name="realm" ref="authRealm"></property> 10 11 <!--声明会话管理器属性--> 12 <property name="sessionManager" ref="sessionManager" ></property> 13 14 <property name="rememberMeManager" ref="rememberMeManager"></property> 15 16 17 <!--<property name="cacheManager" ref="cacheManager"></property>--> 18 </bean>
首先需要在用户登陆后的主界面写一个登出的连接
在shiro的主配置文件中配置,登出的请求经过的过滤器就可以,在shiro的过滤器中有一个名称为logout的过滤器专门为我们处理登出请求:
1 <!--配置shiro认证和授权的过滤器--> 2 <property name="filterChainDefinitions"> 3 <value> 4 <!--对静态资源不拦截--> 5 <!--anon指匿名访问的过滤器,所有匿名用户都可以访问static下面的资源--> 6 /static/*=anon 7 /user/login.do=anon 8 <!--不拦截跳转到主界面的请求--> 9 /user/index.do=anon 10 <!--配置登出请求的过滤器--> 11 /user/logout.do=logout 12 <!--配置/user/list.do必须有user的权限才能访问--> 13 /user/list.do=anon 14 /role/*.do=perms[role] 15 <!--authc指必须经过认证(登录过之后)才能访问的请求 /*代表所有有一个斜杠的请求都要经过认证 --> 16 /*=authc 17 /*/*=authc 18 </value> 19 </property>
shiro为我们提供了一些简单的标签可以在jsp中使用,可以用来控制用户权限做一些操作
1 <shiro:guest> 2 3 Hi there! Please <a href="login.jsp">Login</a> or <a href="signup.jsp">Signup</a> today! 4 5 </shiro:guest>
1 <shiro:user> 2 3 Welcome back John! Not John? Click <a href="login.jsp">here<a> to login. 4 5 </shiro:user>
1 <shiro:authenticated> 2 3 <a href="updateAccount.jsp">Update your contact information</a>. 4 5 </shiro:authenticated>
1 <shiro:notAuthenticated> 2 3 Please <a href="login.jsp">login</a> in order to update your credit card information. 4 5 </shiro:notAuthenticated>
1 Hello, <shiro:principal/>, how are you today?
1 <shiro:hasRole name="administrator"> 2 3 <a href="admin.jsp">Administer the system</a> 4 5 </shiro:hasRole>
1 <shiro:lacksRole name="administrator"> 2 3 Sorry, you are not allowed to administer the system. 4 5 </shiro:lacksRole>
1 <shiro:hasAnyRoles name="developer, project manager, administrator"> 2 3 You are either a developer, project manager, or administrator. 4 5 </shiro:hasAnyRoles>
1 <shiro:hasPermission name="user:create"> 2 3 <a href="createUser.jsp">Create a new User</a> 4 5 </shiro:hasPermission>
1 <shiro:lacksPermission name="user:create"> 2 3 <a href="createUser.jsp">Create a new User</a> 4 5 </shiro:lacksPermission>
标签:pre any 字符串 拦截器 mes error 斜杠 cli isp
原文地址:https://www.cnblogs.com/yanpingping/p/11066799.html