SpringBoot系列:4.session和鉴权—过滤器和拦截器

SpringBoot系列:4.session和鉴权—过滤器和拦截器,第1张

本文主要介绍下,SpringBoot的web项目中,

使用redis保存并共享session,可以实现集群内的登录信息共享。SpringBoot项目中,通过在 application.yml 增加redis的配置,即可实现对session的存储和修改。

那么session是在何时被处理的?session的key又是如何生成的呢?这里实际使用了web项目中的过滤器

在SpringBoot的web项目中,启动的tomcat在处理http请求时,有一个很重要的类: ApplicationFilterChain 。每个http请求在处理时都会通过这个类。这个类负责按顺序处理全部已注册的 Filter ,也就是过滤器。通过实现tomcat中的 Filter 接口,就可以定义一个过滤器。

在SpringBoot中的web项目中,有几个默认的过滤器,其中一个就是用来处理session的: SessionRepositoryFilter

SessionRepositoryFilter 主要的成员是两个接口,都有多个可选的实现类,通过这两个成员就实现了对session的解析。

当然也可以实现一个自己的过滤器,主要有两种方式:

下面我们使用第一种方式实现一个限制指定IP的过滤器:

通过过滤器解析session后,就可以根据session中保存的内容,判断当前登录的用户权限。

这里是通过一个拦截器实现的,在拦截器中可以直接通过 HttpServletRequest.getSession() 方法直接获取session的信息。

一个简单的拦截器实现如下:

定义之后要注册到处理流程中:

先来看下过滤器和拦截器的执行顺序,通过debug得到的执行顺序如下图:

在大部分场景中,过滤器和拦截器都是可互换的,使用哪个都可以。

过滤器和拦截器也有些区别,这里不谈实现和规范的差异,就说下使用中可能涉及的区别:

最后对于过滤器和拦截器的应用场景,说下个人的总结。基于执行顺序,方法参数和SpringBoot中的一些实现类来看。

以上内容属个人学习总结,如有不当之处,欢迎在评论中指正

对于日志和事件记录在每个项目中都会用到,如果在每个manager层中触发时间记录的话,会比较难以扩展和维护,所以可配置的日志和事件记录在项目中会用到!

首先在spring的配置文件中加入hibernate拦截器

Java代码

<bean

id="sessionFactory"

class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

<property

name="entityInterceptor">

<ref

bean="myInterceptor"/>

</property>

</bean>

<bean

id="myInterceptor"

class="com.creawor.cbsms.util.MyInterceptor"

/>

MyInterceptor拦截器为:

Java代码

package

com.creawor.cbsms.util

import

java.io.Serializable

import

java.lang.reflect.InvocationTargetExceptio

n

import

java.lang.reflect.Method

import

java.util.Iterator

import

javacommon.util.ApplicationContextHolder

import

org.hibernate.CallbackException

import

org.hibernate.EntityMode

import

org.hibernate.Interceptor

import

org.hibernate.Transaction

import

org.hibernate.type.Type

import

com.creawor.cbsms.event.EventRecord

import

com.creawor.cbsms.model.CbsChannel

import

com.creawor.cbsms.model.CbsMessage

public

class

MyInterceptor

implements

Interceptor{

//删除时记录时间

public

void

onDelete(Object

obj,

Serializable

arg1,

Object[]

arg2,

String[]

arg3,

Type[]

arg4)

throws

CallbackException

{

//

TODO

Auto-generated

method

stub

String[]

entitys

=

EventRecord.getDeleteEntitysFireEven

t()

for

(String

entityName

:

entitys)

{

if

(entityName.equals(obj.getClass().getSimpleName()))

{

getEventRecordMethod(entityName,

obj,EventRecord.getDeleteInfo())

}

}

}

//修改时记录事件

public

boolean

onFlushDirty(Object

obj,

Serializable

id,

Object[]

currentState,

Object[]

previousState

,

String[]

propertyNames,

Type[]

types){

String[]

entitys

=

EventRecord.getUpdateEntitysFireEven

t()

for

(String

entityName

:

entitys)

{

if

(entityName.equals(obj.getClass().getSimpleName()))

{

getEventRecordMethod(entityName,

obj,

EventRecord.getUpdateInfo())

}

}

return

false

}

public

String

onPrepareStatement(String

arg0)

{

//

TODO

Auto-generated

method

stub

return

arg0

}

//保存时记录事件

public

boolean

onSave(Object

obj,

Serializable

arg1,

Object[]

arg2,

String[]

arg3,

Type[]

arg4)

throws

CallbackException

{

//

TODO

Auto-generated

method

stub

String[]

entitys

=

EventRecord.getSaveEntitysFireEvent()

for

(String

entityName

:

entitys)

{

if

(entityName.equals(obj.getClass().getSimpleName()))

{

getEventRecordMethod(entityName,

obj,EventRecord.getSaveInfo())

}

}

return

false

}

//根据反射机制执行事件记录类中相应的函数

public

void

getEventRecordMethod(String

entityName,Object

obj,String

info){

try

{

Class[]

parameterTypes

=

{String.class,Class.forName(EventRecord.getPrefixPackageName()+entityName)}

Method

method

=

EventRecord.class.getMethod(EventRecord.getPrefixMethodName()+entityName,

parameterTypes)

Object[]

objs

=

{info,

Class.forName(EventRecord.getPrefixPackageName()+entityName).cast(obj)}

method.invoke((EventRecord)ApplicationContextHolder

.getBean("eventRecord"),objs)

}

catch

(Exception

e)

{

//

TODO

Auto-generated

catch

block

e.printStackTrace()

}

}

事件记录类:

Java代码

package

com.creawor.cbsms.event

import

java.sql.Timestamp

import

javacommon.util.ApplicationContextHolder

import

com.creawor.cbsms.dao.CbsEventDao

import

com.creawor.cbsms.model.CbsBsc

import

com.creawor.cbsms.model.CbsBscCells

import

com.creawor.cbsms.model.CbsChannel

import

com.creawor.cbsms.model.CbsEvent

import

com.creawor.cbsms.model.CbsUserRegister

import

com.creawor.cbsms.service.CbsEventManager

import

com.creawor.security.model.PermUser

public

class

EventRecord

{

//

保存时要记录事件的对象

private

static

String[]

saveEntitysFireEvent

=

{

"CbsBscCells",

"CbsChannel",

"CbsBsc"

}

//

删除时要记录事件的对象

private

static

String[]

deleteEntitysFireEvent

=

{

"CbsBscCells",

"CbsChannel",

"CbsBsc"

}

//

更新时要记录事件的对象

private

static

String[]

updateEntitysFireEvent

=

{

"CbsBscCells",

"CbsChannel",

"CbsBsc"

}

//

包的前缀,反射得到类时使用

private

static

String

prefixPackageName

=

"com.creawor.cbsms.model."

//

记录该次 *** 作的登录用户名:EventRecord为session范围

private

String

userName

//

调用函数的前缀,反射执行函数时使用

private

static

String

prefixMethodName

=

"recordFor"

//

执行save时,事件描述

private

static

String

saveInfo

=

"创建"

//

执行delete时,事件描述

private

static

String

deleteInfo

=

"删除"

//

执行update时,事件描述

private

static

String

updateInfo

=

"修改"

private

CbsEventManager

cbsEventManager

//

spring自动注入

public

void

setCbsEventManager(CbsEventManager

cbsEventManager)

{

this.cbsEventManager

=

cbsEventManager

}

public

void

recordForCbsChannel(String

desc,

CbsChannel

channel)

{

StringBuffer

eventDesc

=

new

StringBuffer(desc)

eventDesc.append("频道"

+

channel.getChannelName()).append("[").append(

channel.getChannelNum()).append("]")

record(eventDesc.toString(),

null)

}

public

void

recordForCbsBscCells(String

desc,

CbsBscCells

cell)

{

StringBuffer

eventDesc

=

new

StringBuffer(desc)

eventDesc.append("小区"+cell.getCellName()).append("[").append(

cell.getCellId()).append("]")

record(eventDesc.toString(),

null)

}

public

void

record(String

eventDesc,

String

eventOrigin)

{

CbsEvent

event

=

new

CbsEvent()

event.setEventDesc(userName

+

"

"

+

eventDesc)

event.setEventOrigin(eventOrigin)

event.setStartTime(new

Timestamp(System.currentTimeMillis()))

cbsEventManager.save(event)

}

public

void

setUserName(String

userName)

{

this.userName

=

userName

}

public

static

String[]

getDeleteEntitysFireEven

t()

{

return

deleteEntitysFireEvent

}

public

static

String[]

getSaveEntitysFireEvent()

{

return

saveEntitysFireEvent

}

public

static

String[]

getUpdateEntitysFireEven

t()

{

return

updateEntitysFireEvent

}

public

static

String

getPrefixPackageName()

{

return

prefixPackageName

}

public

static

void

setPrefixPackageName(String

prefixPackageName)

{

EventRecord.prefixPackageName

=

prefixPackageName

}

public

static

String

getPrefixMethodName()

{

return

prefixMethodName

}

public

static

String

getDeleteInfo()

{

return

deleteInfo

}

public

static

String

getSaveInfo()

{

return

saveInfo

}

public

static

String

getUpdateInfo()

{

return

updateInfo

}

}

其中EventRecord 在spring中的配置为:

Java代码

<bean

id="eventRecord"

class="com.creawor.cbsms.event.EventRecord"

scope="session"

autowire="byName"/>

EventRecord 为session范围可以使字段userName记录每次登录人员的姓名

具体在每次登录后从spring容器中得到EventRecord然后set其userName即可!

最后一步要想让session范围生效还要在web.xml中添加配置:

Java代码

<web-app>

...

<listener>

<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>

</listener>

...

</web-app>

这样如果想要记录一个业务bean增删改的 *** 作只需在EventRecord中设置saveEntitysFireEvent,deleteEntitysFireEvent,updateEntitysFireEvent属性即可,同样也可使用配置文件配置,这样都可以使日志和事件的记录变得很简单!


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/bake/7976957.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-12
下一篇 2023-04-12

发表评论

登录后才能评论

评论列表(0条)

保存