一、Django操作cookie
cookie的原理cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存在本地;当浏览器再次访问时,浏览器会自动带上Cookie,这样服务器就能通过Cookie的内容来判断这个是“谁”了。1. 设置cookierep = HttpResponse( . . . ) rep = render( request, . . . ) rep. set_cookie( key, value) rep. set_signed_cookie( key, value, salt= '加密盐' ) 设置cookie的参数:● key, 键● value= ’’, 值● max_age= None , 超时时间 cookie需要延续的时间(以秒为单位)如果参数是\ None `` ,这个cookie会延续到浏览器关闭为止● expires= None , 超时时间( IE requires expires, so set it if hasn’t been already. ) ● path= ’/ ‘, Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问,浏览器只会把cookie回传给带有该路径的页面,这样可以避免将cookie传给站点中的其他的应用。● domain= None , Cookie生效的域名 你可用这个参数来构造一个跨站cookie。如, domain= ”. example. com”所构造的cookie对下面这些站点都是可读的:www. example. com 、www2. example. com 和an. other. sub. domain. example. com 。如果该参数设置为 None ,cookie只能由设置它的站点读取● secure= False , 浏览器将通过HTTPS来回传cookie● httponly= False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)2. 获取cookierequest. COOKIES[ 'key' ] request. get_signed_cookie( key, default= RAISE_ERROR, salt= '' , max_age= None ) 获取cookie的参数:● default: 默认值● salt: 加密盐● max_age: 后台控制过期时间3. 删除cookiedef logout ( request) : ''' 清空cookie的使用场景:退出登录(注销功能) ''' rep = redirect( "/login/" ) rep. delete_cookie( "user" ) return repbaidu. com- - - - - - - - - - - - - > 一级域名- - - - - - - - - - - - - - > 解析出来很多个二级域名
www. baidu. com www1. baidu. com www2. baidu. com ly. baidu. com
127.0 .0 .1 hello. com- - - - - > DNS解析- - - - - > 127.0 .0 .1
secure= False , 浏览器将通过HTTPS来回传cookie
httponly= False 只能http协议传输,无法被JavaScript获取获取cookie和设置cookie也可以通过js实现
1.前端如何设置cookie
在前端,你可以使用 JavaScript 来设置 cookie。
Cookie 是在客户端(浏览器)中存储的小段数据,可以用于存储用户的信息、偏好设置等。
以下是在前端设置 cookie 的基本步骤:1. ** 使用 `document. cookie`** :JavaScript 中可以通过 `document. cookie` 来设置、获取和删除 cookie。`document. cookie` 返回一个包含所有 cookie 的字符串,每个 cookie 以键值对形式表示,用分号和空格分隔。2. ** 设置 Cookie** :要设置一个 cookie,你可以通过将一个键值对添加到 `document. cookie` 字符串中。例如:document. cookie = "username=John Doe; expires=Thu, 18 Dec 2023 12:00:00 UTC; path=/" ; 在这个例子中,设置了一个名为 `username` 的 cookie,它的值是 `John Doe`,并指定了过期时间和路径。3. ** 注意事项** :- `expires` 属性定义了 cookie 的过期时间。过期时间之前,cookie 将一直保存在客户端。如果不设置 `expires`,则 cookie 将成为会话 cookie,在浏览器关闭时删除。- `path` 属性定义了 cookie 可用于哪个路径。默认情况下,cookie 只对设置它的路径及其子路径有效。- 由于浏览器的安全策略,不能在本地文件系统中设置 cookie。你需要在一个服务器环境中才能成功设置和读取 cookie。下面是一个简单的示例,演示如何在前端使用 JavaScript 设置 cookie:
// 设置一个名为 "username" 的 cookie,值为 "John Doe" ,有效期为一天,适用于整个站点
document. cookie = "username=John Doe; expires=" + new Date( new Date( ) . getTime( ) + 24 * 60 * 60 * 1000 ) . toUTCString( ) + "; path=/" ; 注意: 尽管在前端设置 cookie 可以方便地存储一些小量的用户信息,但敏感信息如密码等不应该直接存储在 cookie 中,而应该采用更加安全的方式,比如在后端使用加密存储。
2.localstorage和sessionStorage表示什么
`localStorage` 和 `sessionStorage` 都是浏览器提供的 Web 存储 API,用于在客户端(浏览器)中存储数据。它们提供了一种在浏览器中保存数据的方式,以便在不同页面之间或同一页面的不同会话中共享和访问数据。这两种存储方式的主要区别在于数据的生命周期和作用范围:
1. ** localStorage** :- `localStorage` 是一种持久性的本地存储,数据会一直保存在用户的浏览器中,直到用户主动清除或网站通过代码进行删除。- 数据在同一个浏览器上的不同会话之间是共享的,即使用户关闭浏览器或重新启动计算机数据仍然保留。- 可以存储较大量的数据。2. ** sessionStorage** :- `sessionStorage` 是一种会话级别的本地存储,数据仅在当前会话中有效。当用户关闭浏览器窗口或标签页时,数据会被清除。- 数据在同一个浏览器窗口或标签页的不同页面之间共享,但在新的窗口或标签页中无法访问之前的会话数据。- 存储容量与 `localStorage` 相似,但在某些浏览器中可能会略微有限制。使用示例:
// 设置数据到localStorage
localStorage. setItem( 'username' , 'John' ) ; // 获取数据从localStorage
const username = localStorage. getItem( 'username' ) ; // 移除数据从localStorage
localStorage. removeItem( 'username' ) ; // 设置数据到sessionStorage
sessionStorage. setItem( 'token' , 'abc123' ) ; // 获取数据从sessionStorage
const token = sessionStorage. getItem( 'token' ) ; // 移除数据从sessionStorage
sessionStorage. removeItem( 'token' ) ; 需要注意的是,尽管这些存储方式在浏览器端非常方便,但由于数据是存储在用户的浏览器中,因此不适合存储敏感信息或需要安全性的数据。对于涉及用户隐私和安全的数据,应该使用后端存储或其他加密和保护机制。
二、Django操作session
session的数据是保存在后端,保存在后端的载体其实有很多种,比如:可以把数据保存在数据库、文件、Redis等Django的默认保存位置在数据库中,在django_session表中,这张表是默认生成的。** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** 注意:设置session
def set_Session ( request) : request. session[ 'username' ] = 'jerry' return HttpResponse( 'set_Session' ) '''session的默认过期时间是14天过期时间是可以更改的,如何更改...''' 1 、如何操作session?设置成功一个session值有什么变化?1. 后端会生成一个随机字符串:session_key2. 会把用户设置的信息保存在django_session表中,数据也做了加密处理3. 把数据封装到了request. session里去了4. Django后端把随机字符串保存到了浏览器中5. 随机字符串保存在浏览器中的key= sessionid注意:1. 当设置多个session值的时候,session_key是不变的,变的是session_Data2. 当设置多个session值的时候,django_Session表中只存在一条记录, 即一台电脑的一个浏览器只能保存一条记录问:上述的做法有什么好处?节省MySQL的空间注意:获取session
def get_Session ( request) : print ( request. session. get( 'username' ) ) print ( request. session. get( 'age' ) ) return HttpResponse( 'get_Session' ) 2. 获取session发生了哪些事?1. 浏览器先把sessionid回传到Django的后端2. Django后端获取到sessionid,然后去数据表中根据session_key查询如果查到了,说明之前已经登录过了如果查不到,就返回None 3. 查询出来的数据默认是加密的,Django后端又把数据解密之后封装到request. session中在取session值的时候,就从request. session中取4. session的相关参数request. session. keys( ) request. session. values( ) request. session. items( ) 注意:设置session的过期时间request. session. set_expiry( value) '''* 如果value是个整数,session会在些秒数后失效。* 如果value是个datatime或timedelta,session就会在这个时间后失效。* 如果value是0,用户关闭浏览器session就会失效。* 如果value是None,session会依赖全局session失效策略''' def del_session ( request) : '''清空cookie的两种方式:''' request. session. delete( ) request. session. flush( ) return HttpResponse( 'del_session' ) 注意:1. 清空sessionrequest. session. clear( ) request. session. flush( ) request. session. delete( ) 2. 清空cookie// 设置过期时间为过去的时间,让浏览器自动删除 Cookiedocument. cookie = "cookieName=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;" ;
三、Django中的Session配置
1. 数据库Session
SESSION_ENGINE = 'django.contrib.sessions.backends.db' 2. 缓存Session
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'default' 3. 文件Session
SESSION_ENGINE = 'django.contrib.sessions.backends.file'
SESSION_FILE_PATH = None 4. 缓存+ 数据库
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' 5. 加密Cookie Session
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' 其他公用设置项:
SESSION_COOKIE_NAME = "sessionid"
SESSION_COOKIE_PATH = "/"
SESSION_COOKIE_DOMAIN = None
SESSION_COOKIE_SECURE = False
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_AGE = 1209600
SESSION_EXPIRE_AT_BROWSER_CLOSE = False
SESSION_SAVE_EVERY_REQUEST = False
四、CBV添加装饰器
def login_auth ( func) : def inner ( request, * args, ** kwargs) : if request. session. get( 'username' ) : return func( request, * args, ** kwargs) else : return redirect( '/login/' ) return inner给类中的方法加装饰器的三种方法:注意:先导入
from django. utils. decorators import method_decorator方式1 :直接在类中的方法上面加装饰器
class Login ( View) : @method_decorator ( login_auth) def get ( self, request) : return HttpResponse( "get" ) @method_decorator ( login_auth) def post ( self, request) : return HttpResponse( "post" ) 方式2 :在类的上面给方法加上装饰器
@method_decorator ( login_auth, name= 'get' )
@method_decorator ( login_auth, name= 'post' )
class Login ( View) : @method_decorator ( login_auth) def get ( self, request) : return HttpResponse( "get" ) @method_decorator ( login_auth) def post ( self, request) : return HttpResponse( "post" ) 方式3 :重写dispatch( ) 方法,继承父类的dispatch( ) 方法
class Login ( View) : @method_decorator ( login_auth) def dispatch ( self, request, * args, ** kwargs) : return super ( Login, self) . dispatch( request, * args, ** kwargs) def get ( self, request) : return HttpResponse( "get" ) def post ( self, request) : return HttpResponse( "post" )
五、中间件
什么时候执行中间件?中间件的执行位置在web服务网关接口之后,在路由匹配之前执行的django中自带的有七个中间件:
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware' , 'django.contrib.sessions.middleware.SessionMiddleware' , 'django.middleware.common.CommonMiddleware' , 'django.middleware.csrf.CsrfViewMiddleware' , 'django.contrib.auth.middleware.AuthenticationMiddleware' , 'django.contrib.messages.middleware.MessageMiddleware' , 'django.middleware.clickjacking.XFrameOptionsMiddleware' ,
] 每一个中间件都有它自己独立的功能
注意:我们也可以自己自定义中间件只要是跟全局相关的都可以用中间件来实现- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
那么如何自定义中间件呢?
class SecurityMiddleware ( MiddlewareMixin) : def process_request ( self, request) : pass def process_response ( self, request, response) :pass class SessionMiddleware ( MiddlewareMixin) : def process_request ( self, request) : pass def process_response ( self, request, response) : psssclass CsrfViewMiddleware ( MiddlewareMixin) : def process_request ( self, request) : pass def process_response ( self, request, response) : pass 注意: 中间件就是一个类,然后这个类都继承了 MiddlewareMixinMiddlewareMixin这个类中有几个方法:1. 下面这两个必须要求掌握:process_requestprocess_response2. 下面三个需要了解:process_viewprocess_templateprocess_exception'''这几个方法并不是都要全写,而是,需要几个你就写几个!''' 自定义中间件步骤:1. 在项目名下或者任意的应用名下创建一个文件夹2. 在这个文件夹下面创建一个py文件3. 在该py文件中写一个自定义的类必须要继承MiddlewareMixin4. 写完之后紧接着一定要去配置文件中注册中间件class MyMiddleware1 ( MiddlewareMixin) : '''注意:自定义中间件,要去配置文件(setting.py)中注册''' def process_request ( self, request) : print ( '我是第一个中间件的process_request' ) def process_response ( self, request, response) : '''注意:这个响应函数必须要有返回值,并且返回值必须是response对象,否则会报错:AttributeError: 'NoneType' object has no attribute 'get':param request::param response::return:''' print ( '我是第一个中间件的process_response' ) return response class MyMiddleware2 ( MiddlewareMixin) : def process_request ( self, request) : print ( "我是第二个自定义的中间件process_request" ) def process_response ( self, request, response) : print ( "我是第二个自定义中间件的process_response" ) return response 中间件的执行顺序,输出结果:1. 若process_request函数没有返回值,那么,首先是输出process_request函数中的数据,然后才输出视图函数views中的数据,最后才输出process_response函数中的数据,但是,process_response的执行顺序是倒着走的,即从后往前一个一个执行'''运行结果展示:我是第一个中间件的process_request我是第二个中间件的process_requestfunc我是第二个中间件的process_response我是第一个中间件的process_response''' 2. 若process_request函数有返回值,即:问题:如果我在第一个中间件的process_request中return 返回值,后续的中间件如何走?它会执行同级别的process_response,也就是说:return 拦截了视图views和后面的中间件( 不再执行) '''运行结果展示:我是第一个中间件的process_request我是第一个中间件的process_response''' from django. utils. deprecation import MiddlewareMixinfrom django. shortcuts import render, redirect, HttpResponsedef process_request ( self, request) : print ( '我是第一个中间件的process_request' ) return HttpResponse( '我是第一个中间件的process_request' )
六、csrf跨站请求
1 . csrf跨站请求介绍:CSRF(Cross- Site Request Forgery,跨站请求伪造)是一种网络攻击,攻击者试图在受害者不知情的情况下,通过伪造请求来执行未经授权的操作。这种攻击利用了用户已登录的状态,以用户的名义发送恶意请求,从而绕过了常规的安全措施。2 . CSRF 攻击的原理:攻击者通过各种方式诱使受害者执行一个看似正常但实际上是恶意的请求。这可以通过发送恶意链接、在受害者浏览的页面中插入恶意代码等方式实现。如果受害者当前已登录到一个网站,而该网站没有适当的防护措施,攻击者就可以以受害者的身份发送请求,执行潜在的危险操作,比如更改密码、发表评论、转移资金等。
username
shenfenzheng
< input type = 'text' name= '正规的' >
< input type = 'text' > < input type = 'hidden' name= '冒牌的' > 3. 如何避免这种问题?在form表单中加了一个随机标识,每次提交表单的时候,后端先发起csrf验证( 随机标识) ,说明这个表单就是自己的,若对不上,则直接forbidden。如何解决 Forbidden ( 403 ) CSRF verification failed. Request aborted 问题?
'django.middleware.csrf.CsrfViewMiddleware' , 只有post请求才会有csrf验证
在form表单中加入{ % csrf_token % }
< form action= "" method= "post" > { % csrf_token % } username: < input type = "text" name= "username" > < input type = "submit" value= "提交" >
< / form>
4. 研究ajax发送post请求csrf验证方式1 :如果form表单有值
< form action= "" method= "post" > { % csrf_token % } username: < input type = "text" name= "username" > < input type = "submit" value= "提交" >
< / form> < button class = "btn" > 按钮< / button> < script> $( '.btn' ) . click( function ( ) { $. ajax( { url: '' , type : 'post' , data: { csrfmiddlewaretoken: $( "[name='csrfmiddlewaretoken']" ) . val( ) } , success: function ( ) { } } ) } )
< / script> 方式2 :通过模版变量{ { csrf_token } }
< button class = "btn" > 按钮< / button> < script> $( '.btn' ) . click( function ( ) { $. ajax( { url: '' , type : 'post' , { data: { csrfmiddlewaretoken: '{{ csrf_token }}' } , success: function ( ) { } } ) } )
< / script> 方式3 :前后端分离,使用django官方提供的js文件解决更多细节详见:Djagno官方文档中关于CSRF的内容https: // docs. djangoproject. com/ en/ 1.11 / ref/ csrf/ < button class = "btn" > 按钮< / button>
< script src= "/static/js/my.js" > < / script>
< script> $( '.btn' ) . click( function ( ) { $. ajax( { url: '' , type : 'post' , { { data: { a: 1 } , success: function ( ) { } } ) } )
< / script>
使用django官方提供的js文件
function getCookie( name) { var cookieValue = null; if ( document. cookie & & document. cookie != = '' ) { var cookies = document. cookie. split( ';' ) ; for ( var i = 0 ; i < cookies. length; i+ + ) { var cookie = jQuery. trim( cookies[ i] ) ; // Does this cookie string begin with the name we want?if ( cookie. substring( 0 , name. length + 1 ) == = ( name + '=' ) ) { cookieValue = decodeURIComponent( cookie. substring( name. length + 1 ) ) ; break ; } } } return cookieValue;
}
var csrftoken = getCookie( 'csrftoken' ) ; // 每一次都这么写太麻烦了,可以使用$. ajaxSetup( ) 方法为ajax请求统一设置。function csrfSafeMethod( method) { // these HTTP methods do not require CSRF protectionreturn ( / ^ ( GET| HEAD| OPTIONS| TRACE) $/ . test( method) ) ;
} $. ajaxSetup( { beforeSend: function ( xhr, settings) { if ( !csrfSafeMethod( settings. type ) & & !this. crossDomain) { xhr. setRequestHeader( "X-CSRFToken" , csrftoken) ; } }
} ) ;