security/nonce.go
func Nonce(h http.Handler, opts ...Option) http.Handler {
	headerStorage := nonceHeaderStorage{}
	o := options{
		logger:    handler.OutLogger(),
		generator: timeRandomGenerator,
		getter:    headerStorage,
		setter:    headerStorage,
		age:       45 * time.Second,
	}
	o.apply(opts)

	store := nonceStore{}
	opChan := make(chan func(nonceStore))

	go func() {
		for op := range opChan {
			op(store)
		}
	}()

	go func() {
		for {
			select {
			case <-time.After(5 * time.Minute):
				cleanup(o.age, opChan)
			}
		}
	}()

	setter := func(w http.ResponseWriter, r *http.Request) error {
		nonce, err := generateAndStore(o.age, o.generator, opChan)
		if err != nil {
			return err
		}

		return o.setter.SetNonce(nonce, w, r)
	}

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx := r.Context()

		nonce := o.getter.GetNonce(r)
		if nonce != "" {
			if validateAndRemoveNonce(nonce, o.age, opChan) {
				ctx = context.WithValue(ctx, nonceValueKey, NonceStatus{NonceValid})
			} else {
				ctx = context.WithValue(ctx, nonceValueKey, NonceStatus{NonceInvalid})
			}
		}

		h.ServeHTTP(w, r.WithContext(context.WithValue(ctx, nonceSetterKey, setter)))
	})
}
func Nonce(h http.Handler, opts ...Option) http.Handler {
	headerStorage := nonceHeaderStorage{}
	o := options{
		logger:    handler.OutLogger(),
		generator: timeRandomGenerator,
		getter:    headerStorage,
		setter:    headerStorage,
		age:       45 * time.Second,
	}
	o.apply(opts)

	store := nonceStore{}
	opChan := make(chan func(nonceStore))

	go func() {
		for op := range opChan {
			op(store)
		}
	}()

	go func() {
		for {
			select {
			case <-time.After(5 * time.Minute):
				cleanup(o.age, opChan)
			}
		}
	}()

	setter := func(w http.ResponseWriter, r *http.Request) error {
		nonce, err := generateAndStore(o.age, o.generator, opChan)
		if err != nil {
			return err
		}

		return o.setter.SetNonce(nonce, w, r)
	}

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx := r.Context()

		nonce := o.getter.GetNonce(r)
		if nonce != "" {
			if validateAndRemoveNonce(nonce, o.age, opChan) {
				ctx = context.WithValue(ctx, nonceValueKey, NonceStatus{NonceValid})
			} else {
				ctx = context.WithValue(ctx, nonceValueKey, NonceStatus{NonceInvalid})
			}
		}

		h.ServeHTTP(w, r.WithContext(context.WithValue(ctx, nonceSetterKey, setter)))
	})
}
// Nonce returns a handler that will check each request for the
// existence of a nonce. If a nonce exists, it will be checked for
// expiration. A status will be recorded in the request's context,
// indicating whether there was a nonce in the request, and if so,
// whether it is valid or expired.
//
// The recorded status can later be obtained using the
// NonceValueFromRequest function.
//
// A nonce can be set for later checking using the StoreNonce
// function.