• 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>
    每接触一个新领域,我就像一块掉进水里的海绵,四面八方的养分都让我不断充实。O(∩_∩)O~
  • 相关阅读:
    实验一
    requests/lxml的简单用例
    使用python的cookielib加载已保存的cookie维持登录状态
    计算机系统要素
    python实现部分实例
    ch2
    迷了迷了,外国人都看不懂的英语
    图形学名词解释
    ch17
    ServletConfig
  • 原文地址:https://www.cnblogs.com/zhzcode/p/9756983.html
Copyright © 2020-2023  润新知