SSM+Shiro

1) 表名:用户表(Sys_Users)

Salt:盐(佐料)。为避免被黑客等进行攻击(暴力密码破解),所以一般在注册用户信息时,系统会随机生成一个随机码。在验证时会将密码和随机码进行运算,以验证密码是否正确。

2) 表名:角色表(Sys_Role)

3) 表名:用户角色表(Sys_User_Role)

 

4) 表名:资源表(Sys_Resource)

 

5) 表名:角色权限表(Sys_Role_Permission)

 

RBACRole Basic Access Controll(基于角色的权限控制)

说明:权限验证的基本设计是5张表,扩展后可以设计为12张表

1) 导入jar

 

 

 

常用的数据库连接池:

DBCP C3P0BoneCPProxoolDDConnectionBrokerDBPoolXAPoolPrimroseSmartPoolMiniConnectionPoolManagerDruid

Druid:

Druid连接池最大的优势是可以监控Sql语句的执行,为后期Sql语句的优化提供帮助。

2) 配置web.xml

 1 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
 2     <!-- 1、过滤器 -->
 3     <!-- characterEncodingFilter -->
 4     <!-- 编码过滤器,对所有请求和响应进行编码处理 -->
 5     <filter>
 6         <filter-name>CharacterEncodingFilter</filter-name>
 7         <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
 8         <init-param>
 9             <param-name>encoding</param-name>
10             <param-value>utf-8</param-value>
11         </init-param>
12     </filter>
13     <filter-mapping>
14         <filter-name>CharacterEncodingFilter</filter-name>
15         <url-pattern>/*</url-pattern>
16     </filter-mapping>
17     
18     <!-- HiddenHttpMethodFilter -->
19     <!-- 
20         响应只支持get和post,通过HiddenHttpMethodFilter可以将请求方式转为标准请求方式(解决put和delete不支持的问题)。
21         如果使用ResultFul必须配置 
22     -->
23     <filter>        
24         <filter-name>HiddenHttpMethodFilter</filter-name>
25         <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
26     </filter>
27     <filter-mapping>
28         <filter-name>HiddenHttpMethodFilter</filter-name>
29         <!-- 对所有DispaccherServlet分配的任务进行过滤 -->
30         <servlet-name>springDispatcherServlet</servlet-name>
31     </filter-mapping>
32     
33     <!-- 
34         在web中使用shiro必须配置DelegatingFilterProxy过滤器(实现了Filter接口的Bean对象都会被DelegatingFilterProxy所代理)
35         targetFilterLifecycle:调用过滤器的init()和destroy()方法
36         注意:
37             filte-name的属性名必须和shiro中bean的Id相一致
38     -->
39     <filter>
40         <filter-name>shiroFilter</filter-name>
41         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
42         <init-param>
43             <param-name>targetFilterLifecycle</param-name>
44             <param-value>true</param-value>
45         </init-param>
46     </filter>
47     <filter-mapping>
48         <filter-name>shiroFilter</filter-name>
49         <url-pattern>/*</url-pattern>
50     </filter-mapping>
51     <!-- 2、监听器 -->
52       <!-- ContextLoaderListener -->
53       <!-- 
54           用于监听web容器的启动,当web容器启动时自动对ApplicatoinContext信息进行装配
55           监听器实现了ServletContextListener接口
56       -->
57       <listener>
58           <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
59       </listener>
60       <context-param>
61           <param-name>contextConfigLocation</param-name>
62           <!-- 可以去配置多个value值,各值之间使用","进行分隔 -->
63           <param-value>
64               classpath:applicationContext.xml
65           </param-value>
66       </context-param>  
67   
68      <!-- 3、Servlet -->
69       <!-- DispatcherServlet -->
70       <!-- 多所有请求进行拦截,然后根据请求资源的类型进行任务的分派 -->
71     <servlet>
72         <servlet-name>springDispatcherServlet</servlet-name>
73         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
74         <init-param>
75             <param-name>contextConfigLocation</param-name>
76             <param-value>classpath:spring-mvc.xml</param-value>
77         </init-param>
78         <load-on-startup>1</load-on-startup>
79     </servlet>
80     <servlet-mapping>
81         <servlet-name>springDispatcherServlet</servlet-name>
82         <url-pattern>/</url-pattern>
83     </servlet-mapping>
84     
85     
86 </web-app>

说明:

folder就是普通的文件夹,它和我们window下面使用的文件夹没有任何区别

source folder文件夹是一种特别的文件夹,是folder的子集,source folder中的代码会被编译且存放在web-inf/classes

package也是特殊的文件夹,package是一种物理路径。通过"."区分上下级

 

3) 配置applicationContext.xml

 1 <beans xmlns="http://www.springframework.org/schema/beans"
 2     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 4     <!-- 配置Shiro的核心组件(用于自动注入SecuriyManager) -->
 5     <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
 6         <!-- 1、配置缓存管理器 -->
 7         <property name="cacheManager" ref="cacheManager"/>
 8         <!-- 配置realm -->
 9         <property name="realm" ref="realm"/>
10     </bean>
11     
12     <!-- 1)、配置缓存管理器:对会话的缓存进行管理 -->
13     <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
14         <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
15     </bean>
16     
17     <!-- 2)、配置Realm:实际进行验证的类 -->
18     <bean id="realm" class="cn.hl.realm.UserRealm">        
19     </bean>
20 
21     <!-- 2、 自动调用过滤器的init()和destroy()方法-->
22     <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
23     
24     <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
25           depends-on="lifecycleBeanPostProcessor"/>
26     <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
27         <property name="securityManager" ref="securityManager"/>
28     </bean>
29     
30     <!-- 3、定义过滤器(配置一组过滤器) -->
31     <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
32         <property name="securityManager" ref="securityManager"/>
33         <!-- 配置登录资源路径位置  -->
34         <property name="loginUrl" value="/login.jsp"/>
35         <!-- 配置登录成功跳转的资源路径位置(一般不需要配置。一般都是通过请求处理方法进行处理) -->
36         <!--  
37         <property name="successUrl" value="/index.jsp"/>
38         -->
39         <!-- 配置无权限的跳转的资源路径位置 -->
40         <property name="unauthorizedUrl" value="/unauthorized.jsp"/>
41         <!-- 
42             配置其它资源的访问控制
43             常用内置过滤器对象
44                 anon        :允许匿名访问
45                 authc     :需要通过认证才能访问
46                 roles        :需要具体角色才能访问
47                 user         :指定用户才能访问(较少使用)
48                 logout    :注销当前用户 
49         -->
50         <property name="filterChainDefinitions">
51             <value>
52                 /login.jsp=anon
53                 /unauthorized.jsp=anon
54                 /login =anon
55                 /logout=logout
56                 
57                 # 其余资源需要经过认证后才能访问
58                 /** = authc
59             </value>
60         </property>
61     </bean>
62     
63 </beans>

4) 配置spring-mvc.xml

 1 <beans xmlns="http://www.springframework.org/schema/beans"
 2     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3     xmlns:context="http://www.springframework.org/schema/context"
 4     xmlns:mvc="http://www.springframework.org/schema/mvc"
 5     xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
 6         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 7         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
 8     <!-- 设置静态资源的访问控制 -->
 9     <mvc:default-servlet-handler/>
10     
11     <!-- 启用注解 -->
12     <mvc:annotation-driven></mvc:annotation-driven>
13 
14     <!-- 配置自动扫描 -->
15     <context:component-scan base-package="cn.hl.controller"></context:component-scan>
16     
17     <!-- 配置视图解析器 -->
18     <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
19         <property name="prefix" value="/"></property>
20         <property name="suffix" value=".jsp"></property>
21     </bean>
22 </beans>

5) 编写Controller

 1 @Controller
 2 public class UserController {
 3     @RequestMapping("login")
 4     public String login(String account, String pwd){
 5         System.out.println(SecurityUtils.getSubject());
 6         System.out.println("account = " + account+" | pwd=" + pwd);
 7         //执行登录验证
 8         Subject subject = SecurityUtils.getSubject();
 9         UsernamePasswordToken token = new UsernamePasswordToken(account,pwd);
10         
11         //判断用户是否已经登录(如果没有登录则执行登录验证)
12         if(!subject.isAuthenticated()){
13             try{
14                 //执行登录验证
15                 subject.login(token);
16             }
17             catch(AuthenticationException ex){
18                 System.out.println("提示:" + ex.getMessage());
19                 return "redirect:/login.jsp";
20             }
21         }
22         //已经登录则跳转到"index.jsp"页面
23         return "index";
24     }
25 }

6) 编写Realm

 1 public class UserRealm extends AuthenticatingRealm{
 2     @Override
 3     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
 4         //1、获取用户信息(直接使用参数对象的Token需要进行转换)
 5         //String username = String.valueOf(token.getPrincipal());
 6         
 7         //2、将Token直接转换为UsernamePasswordToken(可以避免转换)
 8         UsernamePasswordToken userToken = (UsernamePasswordToken)token;
 9         String username = userToken.getUsername();
10         
11         //执行登录验证
12         System.out.println("通过数据库读取帐号信息");
13         //从数据库中读取到的内容
14         String user="admin";
15         
16         //对账户名进行验证
17         //User user = service.getUserByAccount(username);
18         if(!user.equals(username)){
19             throw new UnknownAccountException("帐号信息不存在");
20         }
21         //数据库中读取到的密码(String credentials = user.getPassword())
22         String credentials = "123";
23         
24         //对用户进行验证
25         SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, credentials, getName());
26         return info;
27     }
28 }

  • 默认密码验证方式(直接进行比较)
1 [SimpleCredentialsMatcher]
2     public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
3         //获取票证中的密码(用户提交的)
4         Object tokenCredentials = getCredentials(token);
5         //默认的原始密码(数据库中提取的)
6         Object accountCredentials = getCredentials(info);
7         return equals(tokenCredentials, accountCredentials);
8     }
  • 缺点

² 同一个字符串加密加密后的结果是不变的

² 密码容易被破解

  • 解决方案

在密码基础上加点"",加盐后可以使得密码破解的速度降低.

  • 密码生成方式
 1 //加密算法
 2 String algorithmName    ="MD5";
 3 //加密次数
 4 int hashIterations=1024;
 5         
 6 //定义盐
 7 ByteSource salt = ByteSource.Util.bytes("hl");
 8         
 9 //向数据库中存密码时,使用如下方式进行存储
10 //存储时可以考虑使用账号(+其他字段作为盐)
11 Object obj = new SimpleHash(algorithmName, "123", salt, hashIterations);

加入盐的验证

 1 public class UserRealm extends AuthenticatingRealm{
 2 
 3     @Override
 4     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
 5         //1、获取用户信息(直接使用参数对象的Token需要进行转换)
 6         //String username = String.valueOf(token.getPrincipal());
 7         
 8         //2、将Token直接转换为UsernamePasswordToken(可以避免转换)
 9         UsernamePasswordToken userToken = (UsernamePasswordToken)token;
10         String username = userToken.getUsername();
11         
12         //执行登录验证
13         System.out.println("通过数据库读取帐号信息");
14         //从数据库中读取到的内容
15         String user="admin";
16         
17         //对账户名进行验证
18         //User user = service.getUserByAccount(username);
19         if(!user.equals(username)){
20             throw new UnknownAccountException("帐号信息不存在");
21         }
22         //数据库中读取到的密码(String credentials = user.getPassword())
23         //String credentials = "123";
24         //数据库中读取到的密码(数据库中存储的密码)
25         Object hashedCredentials= "e3076e0bf31c666de1bac66b6bbb35d6";
26         
27         //
28         String salt = "hl";
29         ByteSource credentialsSalt = ByteSource.Util.bytes(salt.getBytes());
30         
31         
32         //e3076e0bf31c666de1bac66b6bbb35d6
33         //对用户进行验证(默认的匹配方式是直接进行比较)
34         //SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, credentials, getName());
35         SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
36                 username, 
37                 hashedCredentials, 
38                 credentialsSalt, 
39                 getName());
40         return info;
41     }
42 }

自定义角色

1) 配置

 1         <property name="filterChainDefinitions">
 2             <value>
 3                 /login.jsp=anon
 4                 /unauthorized.jsp=anon
 5                 /login =anon
 6                 /logout=logout
 7                 
 8                 /add.jsp=roles[admin]
 9                 /update.jsp=roles["user,admin"]
10                 /show.jsp=user[root]
11                                 
12                 # 其余资源需要经过认证后才能访问
13                 /** = authc
14             </value>
15         </property>

 

2) 授权

 1 /**
 2  * 不需要授权则直接继承类:AuthenticatingRealm
 3  *    需要授权则需要继承类:AuthorizingRealm
 4  * @author Terry
 5  *
 6  */
 7 public class UserRealm extends AuthorizingRealm{
 8     
 9     /**
10      * 执行登录验证 
11      */
12     @Override
13     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
14         System.out.println("1");
15         //1、获取用户信息(直接使用参数对象的Token需要进行转换)
16         //String username = String.valueOf(token.getPrincipal());
17         
18         //2、将Token直接转换为UsernamePasswordToken(可以避免转换)
19         UsernamePasswordToken userToken = (UsernamePasswordToken)token;
20         String username = userToken.getUsername();
21         
22         //执行登录验证
23         System.out.println("通过数据库读取帐号信息");
24         //从数据库中读取到的内容
25         String user="admin";
26         
27         //对账户名进行验证
28         //User user = service.getUserByAccount(username);
29         if(username==null){
30             throw new UnknownAccountException("帐号信息不存在");
31         }
32         
33         //数据库中读取到的密码(String credentials = user.getPassword())
34         //String credentials = "123";
35         //数据库中读取到的密码(数据库中存储的密码)
36         Object hashedCredentials= "e3076e0bf31c666de1bac66b6bbb35d6";
37         
38         //
39         String salt = "hl";
40         ByteSource credentialsSalt = ByteSource.Util.bytes(salt.getBytes());
41         
42         
43         //e3076e0bf31c666de1bac66b6bbb35d6
44         //对用户进行验证(默认的匹配方式是直接进行比较)
45         //SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, credentials, getName());
46         SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
47                 username, 
48                 hashedCredentials, 
49                 credentialsSalt, 
50                 getName());
51         return info;
52     }
53 
54     /**
55      * 执行授权操作
56      * @param principals
57      * @return
58      */
59     @Override
60     protected AuthorizationInfo doGetAuthorizationInfo(
61             PrincipalCollection principals) {
62         Set<String> roles=new HashSet<String>();
63         
64         System.out.println("授权到用户......");
65         
66         String username= String.valueOf(principals.getPrimaryPrincipal());
67         
68         //从数据库中为不同用户读取角色
69         if("admin".equals(username)){
70             roles.add("admin");
71             roles.add("user");            
72         }
73         else if("sa".equals(username)){
74             roles.add("user");
75         }
76         
77         SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
78         //为用户设置角色(授权)
79         info.setRoles(roles);
80         return info;
81     }
82 }

shiro标签

1) 引入标签库

1 <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

2) 应用标签库

1     <!-- 包含指定角色时显示元素向,否则将隐藏 -->
2     <shiro:hasRole name="admin">
3     <a href="add.jsp">add page</a>
4     </shiro:hasRole>

猜你喜欢

转载自www.cnblogs.com/zhzcode/p/9756983.html
今日推荐