duchaochen / ycbbs-test

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

#通用Mappr 码云地址:https://gitee.com/free/Mapper/wikis/pages?sort_id=208197 github地址:https://github.com/abel533/Mapper ###mybatis的jdbc允许执行多条sql语句 加上这个属性allowMultiQueries=true jdbc.url=jdbc:mysql://47.99.194.149:3306/yc_bbs?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true

###1.配置的变化

将上面的全限定名的org修改为tk就好了
<bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
    <!--扫描所有dao接口的实现,加入到ioc容器中 -->
    <property name="basePackage" value="com.mybatis.plus.mapper"/>
</bean>

###2.接口类变化 创建一个EmployeeMapper接口并且继承Mapper 这里需要注意的是通用接口中的tk.mybatis.mapper.common.Mapper而不是org的 public interface EmployeeMapper extends Mapper { } 以上继承之后就已经有很多公用的增删改查的方法了。

###3.创建一个service业务层来调用 @Service public class EmployeeService { @Autowired private EmployeeMapper employeeMapper;

    /**
     * 获取单个数据信息
     * @param employeeQueryWhere
     * @return
     */
    public Employee getOne(Employee employeeQueryWhere) {
        return  employeeMapper.selectOne(employeeQueryWhere);
    }
}

###4.错误信息 1. nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'yc_bbs.employee' doesn't exist 以上问题表示表名和实体类的名称不一致,所以我们需要使用@table注解@Table(name = "tabple_emp") @Data @AllArgsConstructor @NoArgsConstructor @Accessors(chain = true) @Table(name = "tabple_emp") public class Employee { private Integer empId; private String empName; private Double empSalary; private Integer empAge; } 2. 还有一个@Column注解是实体的属性名和数据库的字段名不一致可以使用此注解 3. 如果要根据主键查询需要在实体的主键字段上加上@Id这个注解, 要不然mapper认为是组合主键,会将所有的字段都当做主键拿去查询 @Id private Integer empId;

        employeeMapper.selectByPrimaryKey(empId);
    注意所有带有ByPrimaryKey的都需要使用@id注解的
    
    //获取自增的值
    @GeneratedValue(strategy = GenerationType.IDENTITY)
        
    如果字段是数据库中没有的我们需要使用@Transient注解来过滤,否则会报异常
    @Transient
    private Integer editEmpName;

###mybatis-ehcache缓存整合 1.导入ehcache包 net.sf.ehcache ehcache-core 2.6.11 2.导入mybatis-ehcache整合包 org.mybatis.caches mybatis-ehcache 1.1.0

3.实现Cache接口,在使用ehcache或者redis,等等缓存aip编写代码即可,
  这里使用ehcache缓存,所以整合包都已经帮我们实现了
  添加一个ehcache.xml
  <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
      <!--diskStore:缓存数据持久化的目录 地址  -->
      <diskStore path="F:\develop\ehcache" />
      <!-- diskPersistent="true"表示为永久保存-->
      <defaultCache
              maxElementsInMemory="1000"
              maxElementsOnDisk="10000000"
              eternal="false"
              overflowToDisk="false"
              diskPersistent="true"
              timeToIdleSeconds="120"
              timeToLiveSeconds="120"
              diskExpiryThreadIntervalSeconds="120"
              memoryStoreEvictionPolicy="LRU">
      </defaultCache>
  </ehcache>
  
  4.然后开启mybatis缓存
   <settings>
     <!--开启二级缓存-->
     <setting name="cacheEnabled" value="true"/>
    </settings>
    
  5.然后在每个mapper.xml中添加
      <!--开启二级缓存-->
      <!--单位为毫秒-->
      <cache type="org.mybatis.caches.ehcache.EhcacheCache">
          <!--过期时间-->
          <property name="timeToIdleSeconds" value="3600"/>
          <property name="timeToLiveSeconds" value="3600"/>
          <!--同ehcache参数maxElementsInMemory-->
          <property name="maxEntriesLocalHeap" value="1000"/>
          <!--同ehcache参数maxElementsOnDisk,磁盘上允许的最大元素数。0表示无线。-->
          <property name="maxEntriesLocalDisk" value="10000000"/>
          <property name="memoryStoreEvictionPolicy" value="LRU"/>
      </cache>

###springmvc的拦截器、适配器(conversionService)、过滤器 1.过滤器和springmvc没有关系 2.拦截器是处理请求的各个阶段的 3.适配器conversionService是处理参数绑定阶段

shiro的过虑器简称

过滤器简称	对应的java类
anon	org.apache.shiro.web.filter.authc.AnonymousFilter
authc	org.apache.shiro.web.filter.authc.FormAuthenticationFilter
authcBasic	org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
perms	org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
port	org.apache.shiro.web.filter.authz.PortFilter
rest	org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
roles	org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
ssl	org.apache.shiro.web.filter.authz.SslFilter
user	org.apache.shiro.web.filter.authc.UserFilter
logout	org.apache.shiro.web.filter.authc.LogoutFilter

non:例子/admins/**=anon 没有参数,表示可以匿名使用。
authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,FormAuthenticationFilter是表单认证,没有参数 
perms:例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,
例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。
user:例如/admins/user/**=user没有参数表示必须存在用户, 身份认证通过或通过记住我认证通过的可以访问,当登入操作时不做检查

###shiro简单使用

 1. 创建一个自定义的CustomRealm类,来做认证和授权使用的,需要继承AuthorizingRealm类,重写以下2个方法
    1)doGetAuthenticationInfo认证发放,所有需要认证的都会经过次方法
    2)doGetAuthorizationInfo授权方法,所有用户要授权的方法都会在此方法中授权才可以访问,
    需要跟@RequiresPermissions注解来配合使用详情见程序中代码。
    加上@RequiresPermissions注解拦截才会激活Realm认证和授权方法.
    
    
 2. 然后将此CustomRealm类挂在到spring中,applicationContext-shiro.xml配置
    <!-- 自定义 realm -->
    <bean id="userRealm" class="com.ycbbs.crud.shiro.realm.CustomRealm">
        <!--将认证需要的凭证匹配器注入到自定义realm中-->
        <property name="credentialsMatcher" ref="credentialsMatcher"/>
    </bean>
    <!-- 凭证匹配器,该类是为了和用户的密码加盐来进行匹配是否能认证成功的,使用md5的算法来加密1次判断 -->
     <bean id="credentialsMatcher"
           class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
         <property name="hashAlgorithmName" value="md5" />
         <property name="hashIterations" value="1" />
     </bean>
     
 3.创建一个安全管理器(DefaultWebSecurityManager),并且将自定义CustomRealm类注入到安全管理器的类中
   applicationContext-shiro.xml配置如下:
    <!-- 安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="userRealm" />
    </bean>
    
 4. 开启shiro的注解支持(@RequiresPermissions("item:query"))这种形式
    注意:这段配置必须写在springmvc的配置文件中,也就是需要前端控制器来控制springmvc.xml配置
    <!-- 开启aop,对类代理 -->
    <aop:config proxy-target-class="true"/>
    <!-- 开启shiro注解支持 -->
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
         <!-- 这里是将securityManager安全管理器注入进去 -->
        <property name="securityManager" ref="securityManager" />
    </bean>

 5.最后需要配置shiro的过滤器
    applicationContext-shiro.xml配置如下:
    5.1  <!-- Shiro 的Web过滤器 -->
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
             <!-- 注入安全管理器-->
             <property name="securityManager" ref="securityManager" />
             
             <!-- loginUrl认证提交地址,如果没有认证将会请求此地址进行认证,
             请求此地址将由formAuthenticationFilter进行表单认证,注意此处在restfull下是无效的,需要自己处理 -->
             <property name="loginUrl" value="/login" />
             <!--认证失败的跳转地址-->
             <property name="unauthorizedUrl" value="/refuse" />
             <!-- 过虑器链定义,从上向下顺序执行,一般将/**放在最下边 -->
             <property name="filterChainDefinitions">
                 <value>
                     <!--退出,请求 /logout地址,shiro去清除session-->
                     /logout = logout
                     <!-- 所有匿名访问 -->
                     <!--/login = anon-->
                     <!--所有的都需要认真-->
                     /** = authc
                 </value>
             </property>
        </bean>
        
    5.2最后web.xml中配置shiro过滤器
        <!-- shiro过虑器,DelegatingFilterProxy通过代理模式将spring容器中的bean和filter关联起来 -->
        <filter>
            <filter-name>shiroFilter</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
            <!-- 设置true由servlet容器控制filter的生命周期 -->
            <init-param>
                <param-name>targetFilterLifecycle</param-name>
                <param-value>true</param-value>
            </init-param>
            <!-- 设置spring容器filter的bean id,如果不设置则找与filter-name一致的bean-->
            <init-param>
                <param-name>targetBeanName</param-name>
                <param-value>shiroFilter</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>shiroFilter</filter-name>
              <!-- 拦截所有 -->
            <url-pattern>/*</url-pattern>
        </filter-mapping>
 
 6.@RequiresPermissions使用(如果没有加这个注解的方法,只要认证通过了之后都可以访问,否则直接访问会报错)
    6.1)在自定义的CustomRealm类中的授权方法中添加:
        simpleAuthorizationInfo.addStringPermission("item:update");(这里写的是死的,也可以将数据库中获取的动态add到simpleAuthorizationInfo中)
      表示用户有此权限那么在请求的方法上添加@RequiresPermissions("item:update")表示该方法是可以授权通过的。
      以下实例代码:
        @RequestMapping("/test03")
        @RequiresPermissions("item:update")
        public YcBbsResult test03() throws CustomException {
            Subject subject = SecurityUtils.getSubject();
            return YcBbsResult.build(200,"这个已授权:item:update",subject.getPrincipal());
        }
    6.2)用户中授权标记集合中是没有此字符串(item:delete),也就是表示此方法是授权不通过。
      直接会执行/refuse控制器中,这个在shiro过滤器中已经配置
    @RequestMapping("/test04")
    @RequiresPermissions("item:delete")
    public YcBbsResult test04() throws CustomException {
        Subject subject = SecurityUtils.getSubject();
        return YcBbsResult.build(200,"测试无授权",subject.getPrincipal());
    }
    
    重点注意:如果不加@RequiresPermissions注解的情况下,认证成功之后,将不会进行授权匹配的,
    也就是说不会触发CustomRealm类中的doGetAuthorizationInfo方法。
    
 7.添加ehcache缓存
    1)添加shiro-ehcache.xml
    2)applicationContext-shiro.xml配置
        <!-- 加缓存管理器,直接注入到securityManager安全管理器即可 -->
        <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
            <!--创建一个缓存xml-->
            <property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml"/>
        </bean>
    3)将cacheManager注入到安全管理器(securityManager)中
    4)清空缓存,需要定义在CustomRealm类中,在权限更新的时候调用

###shiro实现记住我 1.创建rememberMeManager管理器,记录cookie

2.将rememberMeManager管理器注入到安全管理器中
    代码:
    <!-- 安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="userRealm" />
        <!-- 注入缓存管理器 -->
        <property name="cacheManager" ref="cacheManager"/>
        <!--注入session管理器-->
        <!--<property name="sessionManager" ref="sessionManager" />-->
        <!--注入记住我-->
        <property name="rememberMeManager" ref="rememberMeManager"/>
    </bean> 
    
3.自定义form认证过虑器,修改过滤去默认的接收前端传参的名称
  <!-- 基于Form表单的身份验证过滤器,不配置将也会注册此过虑器,表单中的用户账号、密码及loginurl将采用默认值,建议配置 -->
  <bean id="formAuthenticationFilter"
        class="com.ycbbs.crud.shiro.filter.CustomFormAuthenticationFilter">
      <!-- 表单中账号的input名称 -->
      <property name="usernameParam" value="username" />
      <!-- 表单中密码的input名称 -->
      <property name="passwordParam" value="password" />
      <!--表单中的记住我的checkbox名称-->
      <property name="rememberMeParam" value="rememberMe" />
  </bean>

在前后端分离情况下使用jwt+shiro来认证与授权

问题:在每次系统登录时使用currentUser.login(new JWTToken(token));进入realm来认证,认证成功之后
第二次访问其它controller有需要重新认证了,问题就在于前后端分离,后端认为每次请求的都是新的用户。
这个时候就需要我们做一个唯一的token在作为认证的标识,第二次或者第三次访问controller时根据token来获取验证了
token:就是将用户名加密的唯一码。

1.每次访问时在ajax中的heaners中带一个token过来,
    一般第一次是token是为空,所以在登录时后台给将登录的用户名和密码来生成一个token。
    注意:需要在登录时将用户名密码跟数据库中匹配一次,如果对应在做其他业务.
2.需要一个jwt的过滤器以及自定义一个shiro的token类来创建token.
3.在过滤器中来使用token获取用户名和缓存或者数据库中查询得来的密码来做jwt校验,然后提交到realm中,
    如果token为空那么就不会提交到realm
4.授权起作用必须要使用@RequiresPermissions注解,每次请求的contrller方法时遇到RequiresPermissions注解就会被拦截,
这个时候就可以在拦截器执行登录与授权就可以了。

记住一定要在controller访问方法上面加上权限全解@RequiresPermissions,才会进入realm授权方法

总结

About


Languages

Language:Java 100.0%